mirror of
https://gitee.com/ant-design-blazor/ant-design-blazor.git
synced 2024-12-05 05:27:37 +08:00
feat(module: input): add ChangeOnInput, modify the default binding behavior to bind value in the onchange event (#2838)
* feat(module: input): add ChangeOnInput, modify the default binding behavior to bind in the onchange event * fix can't change immediately when debounce milliseconds is 0 * add tests
This commit is contained in:
parent
47c07b858f
commit
2a59463f8e
@ -46,7 +46,7 @@ namespace AntDesign
|
||||
public RenderFragment AddOnAfter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow to remove input content with clear icon
|
||||
/// Allow to remove input content with clear icon
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool AllowClear { get; set; }
|
||||
@ -77,14 +77,28 @@ namespace AntDesign
|
||||
public bool Bordered { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Delays the processing of the KeyUp event until the user has stopped
|
||||
/// Whether to change value on input
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ChangeOnInput { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Delays the processing of the KeyUp event until the user has stopped
|
||||
/// typing for a predetermined amount of time
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int DebounceMilliseconds { get; set; } = 250;
|
||||
public int DebounceMilliseconds
|
||||
{
|
||||
get => _debounceMilliseconds;
|
||||
set
|
||||
{
|
||||
_debounceMilliseconds = value;
|
||||
ChangeOnInput = value >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The initial input content
|
||||
/// The initial input content
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public TValue DefaultValue { get; set; }
|
||||
@ -186,7 +200,6 @@ namespace AntDesign
|
||||
[Parameter]
|
||||
public RenderFragment Suffix { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The type of input, see: MDN(use `Input.TextArea` instead of type=`textarea`)
|
||||
/// </summary>
|
||||
@ -194,10 +207,10 @@ namespace AntDesign
|
||||
public string Type { get; set; } = "text";
|
||||
|
||||
/// <summary>
|
||||
/// Set CSS style of wrapper. Is used when component has visible: Prefix/Suffix
|
||||
/// Set CSS style of wrapper. Is used when component has visible: Prefix/Suffix
|
||||
/// or has paramter set <seealso cref="AllowClear"/> or for components: <see cref="InputPassword"/>
|
||||
/// and <see cref="Search"/>. In these cases, html span elements is used
|
||||
/// to wrap the html input element.
|
||||
/// and <see cref="Search"/>. In these cases, html span elements is used
|
||||
/// to wrap the html input element.
|
||||
/// <seealso cref="WrapperStyle"/> is used on the span element.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
@ -228,7 +241,7 @@ namespace AntDesign
|
||||
|
||||
/// <summary>
|
||||
/// Removes focus from input element.
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
public async Task Blur()
|
||||
{
|
||||
await BlurAsync(Ref);
|
||||
@ -251,8 +264,7 @@ namespace AntDesign
|
||||
private Timer _debounceTimer;
|
||||
private bool _autoFocus;
|
||||
private bool _isInitialized;
|
||||
|
||||
private bool DebounceEnabled => DebounceMilliseconds != 0;
|
||||
private int _debounceMilliseconds = 250;
|
||||
|
||||
protected bool IsFocused { get; set; }
|
||||
|
||||
@ -335,23 +347,17 @@ namespace AntDesign
|
||||
SetClasses();
|
||||
}
|
||||
|
||||
protected virtual async Task OnChangeAsync(ChangeEventArgs args)
|
||||
protected virtual Task OnChangeAsync(ChangeEventArgs args)
|
||||
{
|
||||
if (CurrentValueAsString != args?.Value?.ToString())
|
||||
{
|
||||
CurrentValueAsString = args?.Value?.ToString();
|
||||
if (OnChange.HasDelegate)
|
||||
{
|
||||
await OnChange.InvokeAsync(Value);
|
||||
}
|
||||
}
|
||||
ChangeValue(true);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected async Task OnKeyPressAsync(KeyboardEventArgs args)
|
||||
{
|
||||
if (args?.Key == "Enter" && InputType != "textarea")
|
||||
{
|
||||
await ChangeValue(true);
|
||||
ChangeValue(true);
|
||||
if (EnableOnPressEnter)
|
||||
{
|
||||
await OnPressEnter.InvokeAsync(args);
|
||||
@ -364,7 +370,7 @@ namespace AntDesign
|
||||
|
||||
protected async Task OnKeyUpAsync(KeyboardEventArgs args)
|
||||
{
|
||||
await ChangeValue();
|
||||
ChangeValue();
|
||||
|
||||
if (OnkeyUp.HasDelegate) await OnkeyUp.InvokeAsync(args);
|
||||
}
|
||||
@ -376,7 +382,7 @@ namespace AntDesign
|
||||
|
||||
protected async Task OnMouseUpAsync(MouseEventArgs args)
|
||||
{
|
||||
await ChangeValue(true);
|
||||
ChangeValue(true);
|
||||
|
||||
if (OnMouseUp.HasDelegate) await OnMouseUp.InvokeAsync(args);
|
||||
}
|
||||
@ -391,8 +397,6 @@ namespace AntDesign
|
||||
_compositionInputting = false;
|
||||
}
|
||||
|
||||
await ChangeValue(true);
|
||||
|
||||
if (OnBlur.HasDelegate)
|
||||
{
|
||||
await OnBlur.InvokeAsync(e);
|
||||
@ -455,14 +459,14 @@ namespace AntDesign
|
||||
|
||||
protected void DebounceTimerIntervalOnTick(object state)
|
||||
{
|
||||
InvokeAsync(async () => await ChangeValue(true));
|
||||
InvokeAsync(() => ChangeValue(true));
|
||||
}
|
||||
|
||||
private async Task ChangeValue(bool ignoreDebounce = false)
|
||||
protected void ChangeValue(bool force = false)
|
||||
{
|
||||
if (DebounceEnabled)
|
||||
if (ChangeOnInput)
|
||||
{
|
||||
if (!ignoreDebounce)
|
||||
if (_debounceMilliseconds > 0 && !force)
|
||||
{
|
||||
DebounceChangeValue();
|
||||
return;
|
||||
@ -470,11 +474,14 @@ namespace AntDesign
|
||||
|
||||
if (_debounceTimer != null)
|
||||
{
|
||||
await _debounceTimer.DisposeAsync();
|
||||
|
||||
_debounceTimer.Dispose();
|
||||
_debounceTimer = null;
|
||||
}
|
||||
}
|
||||
else if (!force)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_compositionInputting)
|
||||
{
|
||||
@ -483,7 +490,7 @@ namespace AntDesign
|
||||
CurrentValue = _inputValue;
|
||||
if (OnChange.HasDelegate)
|
||||
{
|
||||
await OnChange.InvokeAsync(Value);
|
||||
OnChange.InvokeAsync(Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -653,6 +660,7 @@ namespace AntDesign
|
||||
builder.AddAttribute(72, "onkeypress", CallbackFactory.Create(this, OnKeyPressAsync));
|
||||
builder.AddAttribute(73, "onkeydown", CallbackFactory.Create(this, OnkeyDownAsync));
|
||||
builder.AddAttribute(74, "onkeyup", CallbackFactory.Create(this, OnKeyUpAsync));
|
||||
|
||||
builder.AddAttribute(75, "oninput", CallbackFactory.Create(this, OnInputAsync));
|
||||
|
||||
//TODO: Use built in @onfocus once https://github.com/dotnet/aspnetcore/issues/30070 is solved
|
||||
|
@ -0,0 +1,18 @@
|
||||
<div>
|
||||
onchange:
|
||||
<Input Placeholder="onblur change" @bind-Value="@txtValue" />
|
||||
<br />
|
||||
<br />
|
||||
oninput:
|
||||
<Input Placeholder="oninput change" @bind-Value="@txtValue" ChangeOnInput />
|
||||
<br />
|
||||
<br />
|
||||
oninput without debounce:
|
||||
<Input Placeholder="oninput change" @bind-Value="@txtValue" DebounceMilliseconds="0" />
|
||||
<br />
|
||||
<br />
|
||||
<Text>@txtValue</Text>
|
||||
</div>
|
||||
@code{
|
||||
string txtValue { get; set; }
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
---
|
||||
order: 0
|
||||
title:
|
||||
zh-CN: 输入时变更
|
||||
en-US: Change on input
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
从 0.13.0 开始,输入框的值绑定事件默认变为 `onchange`,如果需要在输入时绑定,请设置 `ChangeOnInput`。
|
||||
|
||||
> 注意:当在 Server Side 使用输入时变更,会存在绑定延迟和文本回退问题,可尝试加大 `DebounceMilliseconds` 的值来解决。[#579](https://github.com/ant-design-blazor/ant-design-blazor/issues/579)
|
||||
|
||||
|
||||
## en-US
|
||||
|
||||
Starting from 0.13.0, the input box value binding event defaults to 'onchange'. If you need to bind at input time, set 'ChangeOnInput'.
|
||||
|
||||
> Note: When using input changes on the Server Side, there are binding delays and text rollback issues, you can try to address them by increasing the values of `DebounceMilliseconds`. [#579](https://github.com/ant-design-blazor/ant-design-blazor/issues/579)
|
@ -25,8 +25,9 @@ A basic widget for getting the user input is a text field. Keyboard and mouse ca
|
||||
| AllowComplete | Controls the autocomplete attribute of the input HTML element. | boolean | true |
|
||||
| AutoFocus | Focus on input element. | boolean | false
|
||||
| Bordered | Whether has border style | boolean | true
|
||||
| ChangeOnInput | Whether to change on input | boolean | false |
|
||||
| CultureInfo | What Culture will be used when converting string to value and value to string. Useful for InputNumber component. | CultureInfo | CultureInfo.CurrentCulture |
|
||||
| DebounceMilliseconds | Delays the processing of the KeyUp event until the user has stopped typing for a predetermined amount of time | int | 250 |
|
||||
| DebounceMilliseconds | Delays the processing of the KeyUp event until the user has stopped typing for a predetermined amount of time. The setting will enable 'ChangeOnInput'. | int | 250 |
|
||||
| DefaultValue | The initial input content | TValue | - |
|
||||
| Disabled | Whether the input is disabled. | boolean | false |
|
||||
| InputElementSuffixClass |Css class that will be added to input element class as the last class entry. | string | - | 0.9
|
||||
|
@ -16,6 +16,8 @@ cover: https://gw.alipayobjects.com/zos/alicdn/xS9YEJhfe/Input.svg
|
||||
|
||||
## API
|
||||
|
||||
### Common API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ---------------- | -------------------------------------------- | ------------- | --------- |
|
||||
| AddOnBefore | 带标签的 input,设置前置标签 | RenderFragment | - |
|
||||
@ -24,8 +26,9 @@ cover: https://gw.alipayobjects.com/zos/alicdn/xS9YEJhfe/Input.svg
|
||||
| AllowComplete | 控制 Input HTML 元素的自动完成属性. | boolean | true |
|
||||
| AutoFocus | 自动聚焦. | boolean | false
|
||||
| Bordered | 是否有边框 | boolean | true
|
||||
| ChangeOnInput | 是否输入时变更 | boolean | false |
|
||||
| CultureInfo | 文本格式化时区域本地化选项 | CultureInfo | CultureInfo.CurrentCulture |
|
||||
| DebounceMilliseconds | 延迟 KeyUp 事件的处理,直到用户停止输入一段预定的时间 | int | 250 |
|
||||
| DebounceMilliseconds | 延迟 KeyUp 事件的处理,直到用户停止输入一段预定的时间,设置后会开启 `ChangeOnInput` | int | 250 |
|
||||
| DefaultValue |输入框默认内容 | TValue | - |
|
||||
| Disabled |是否禁用状态,默认为 false | boolean | false |
|
||||
| InputElementSuffixClass |作为最后一个Css Class 添加到Input的类目中. | string | - | 0.9
|
||||
|
@ -122,6 +122,19 @@
|
||||
cut.Find("span.ant-input-clear-icon").GetAttribute("style").Should().Contain("visibility: hidden");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Input_default_change()
|
||||
{
|
||||
//Arrange
|
||||
string? value = null;
|
||||
var cut = Render<AntDesign.Input<string>>(@<AntDesign.Input @bind-Value=@value />);
|
||||
//Act
|
||||
cut.Find("input").Input("newValue"); // get value on input
|
||||
cut.Find("input").Change("newValue"); // binding value on change
|
||||
//Assert
|
||||
cut.Instance.Value.Should().Be("newValue");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Input_Debounce_sets_value()
|
||||
{
|
||||
@ -133,8 +146,39 @@
|
||||
cut.Find("input").Input("newValue");
|
||||
cut.Find("input").KeyUp(String.Empty);
|
||||
//Assert
|
||||
await Task.Delay(debounce + 100);
|
||||
await Task.Delay(debounce);
|
||||
|
||||
cut.Instance.Value.Should().Be("newValue");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Input_Debounce_sets_zero()
|
||||
{
|
||||
//Arrange
|
||||
string? value = null;
|
||||
int debounce = 0;
|
||||
var cut = Render<AntDesign.Input<string>>(@<AntDesign.Input @bind-Value=@value DebounceMilliseconds="@debounce" />);
|
||||
//Act
|
||||
cut.Find("input").Input("newValue");
|
||||
cut.Find("input").KeyUp(String.Empty);
|
||||
//Assert
|
||||
|
||||
cut.Instance.Value.Should().Be("newValue");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Input_with_changeOnInput()
|
||||
{
|
||||
//Arrange
|
||||
string? value = null;
|
||||
|
||||
var cut = Render<AntDesign.Input<string>>(@<AntDesign.Input @bind-Value=@value ChangeOnInput />);
|
||||
//Act
|
||||
cut.Find("input").Input("newValue");
|
||||
cut.Find("input").KeyUp(String.Empty);
|
||||
//Assert
|
||||
await Task.Delay(250);
|
||||
|
||||
cut.Instance.Value.Should().Be("newValue");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user