Description
When TelerikTextBox is used inside an HTML <form> with DebounceDelay configured, submitting the form (e.g. pressing Enter or clicking a submit button) races against the debounce timer. The ValueChanged callback has not yet fired by the time the form's onsubmit handler runs, so the component's internal state still holds the previous value — not the one the user typed.
The only workaround we found is to await Task.Delay(DebounceDelay + buffer) inside the submit handler to artificially wait for the debounce window to expire before reading the value. This is fragile, unreliable under load, and a clear code smell.
Expected behavior
When the form is submitted, TelerikTextBox should immediately flush its pending debounced value (i.e. fire ValueChanged synchronously or at least before the browser submit event propagates), so the calling component has the correct, up-to-date value at the moment the submit handler runs.
Alternatively, TelerikTextBox should expose a way to imperatively commit the current value (e.g. a public CommitValue() method, or a @ref-accessible flush API).
Steps to reproduce
- Place a
TelerikTextBoxwithDebounceDelayinside an HTML<form>. - Bind the value using
Value+ValueChanged(two-way binding pattern). - Add a submit button or handle
Entervia@onsubmit. - Type text quickly and immediately press Enter before the debounce window expires.
- Observe that
ValueChangedhas not fired yet, so the submitted value is stale.
Minimal reproducible example:
@* SearchInput.razor *@
<form @onsubmit="HandleFormSubmit" @onsubmit:preventDefault>
<TelerikTextBox Value="@_value"
ValueChanged="@HandleValueChanged"
Placeholder="Search..."
DebounceDelay="@DebounceDelay" />
<button type="submit">Search</button>
</form>
<p>Submitted value: <strong>@_submittedValue</strong></p>
<p>Current internal value: <strong>@_value</strong></p>
@code {
// Simulates a real-world DebounceDelay parameter passed in by a parent
private int DebounceDelay { get; set; } = 300;
private string _value = string.Empty;
private string _submittedValue = string.Empty;
private void HandleValueChanged(string value)
{
// This fires only after DebounceDelay ms have passed since the last keystroke.
// If the user presses Enter before that window expires, this has NOT been called yet.
_value = value;
}
private async Task HandleFormSubmit()
{
// PROBLEM: at this point, if the user typed and immediately hit Enter,
// _value may still hold the OLD value because HandleValueChanged
// hasn't been called yet (debounce hasn't fired).
// WORKAROUND (bad practice — fragile, timing-dependent):
// await Task.Delay(DebounceDelay + 50);
// What we WANT: a way to tell TelerikTextBox "flush now"
// so that _value is guaranteed to reflect what the user typed.
_submittedValue = _value; // may be stale without the Task.Delay hack
await Task.CompletedTask;
}
}To observe the bug without the workaround:
- Remove / comment out the
Task.Delayline. - Set
DebounceDelayto something perceptible like300ms. - Type quickly in the box and press Enter immediately.
- "Submitted value" will show the previous value, not what you just typed.
Current workaround
private async Task HandleFormSubmit()
{
// Must wait for debounce to expire before _value is reliable
if (DebounceDelay > 0)
await Task.Delay(DebounceDelay + 50); // 50 ms buffer for safety
await OnSubmit.InvokeAsync();
}This is problematic because:
- It introduces an artificial, fixed delay on every form submit (even when no debounce is pending).
- The buffer (
+50 ms) is arbitrary and can still fail under CPU load or slow devices. - It makes the submit handler non-deterministic and hard to test.
What we are asking for
One of the following solutions:
Automatic flush on submit —
TelerikTextBoxshould detect that the parent form is being submitted (via a form context orEditContext) and immediately fireValueChangedwith the current raw input value, bypassing the remaining debounce wait.Imperative flush via
@ref— Expose aFlushValue()/CommitValue()method on the component ref so the consumer can call it before reading the bound value:
@* Desired API *@
<TelerikTextBox @ref="_textBoxRef" ... DebounceDelay="300" />
private TelerikTextBox _textBoxRef;
private async Task HandleFormSubmit()
{
await _textBoxRef.FlushValueAsync(); // fires ValueChanged immediately
_submittedValue = _value; // now guaranteed to be up-to-date
}