Skip to content

Commit ed2e900

Browse files
authored
feat(AutoComplete): add IsClearable parameter (#6758)
* feat: 支持清空小按钮 * feat: 增加 ClearIcon 功能 * doc: 更新示例文档 * doc: 增加多语言 * doc: 更新文档 * test: 增加单元测试 * refactor: 移动到 Auto 组件中 * test: 增加单元测试
1 parent 47d21d5 commit ed2e900

File tree

7 files changed

+79
-6
lines changed

7 files changed

+79
-6
lines changed

src/BootstrapBlazor.Server/Components/Samples/AutoCompletes.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
<h4>@Localizer["Description"]</h4>
77

88
<DemoBlock Title="@Localizer["Block1Title"]" Introduction="@Localizer["Block1Intro"]" Name="Normal">
9-
<section ignore>@Localizer["NormalDescription"]</section>
9+
<section ignore>@((MarkupString)Localizer["NormalDescription"].Value)</section>
1010
<div style="width: 200px;">
11-
<AutoComplete Value="@_value" Items="@StaticItems" IsSelectAllTextOnFocus="true"></AutoComplete>
11+
<AutoComplete Value="@_value" Items="@StaticItems" IsSelectAllTextOnFocus="true" IsClearable></AutoComplete>
1212
</div>
1313
</DemoBlock>
1414

src/BootstrapBlazor.Server/Locales/en-US.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2121,7 +2121,7 @@
21212121
"OnSelectedItemChangedTitle": "OnSelectedItemChanged",
21222122
"OnSelectedItemChangedIntro": "Click the dropdown item or <kbd>Enter</kbd> trigger the callback",
21232123
"OnValueChanged": "Callback for the Value changed",
2124-
"NormalDescription": "In this example, type 123 strings to display the viewing effect, automatically give the component initialization to the auto-prompt dataset, and the dataset does not change",
2124+
"NormalDescription": "In this example, type 123 strings to display the viewing effect, automatically give the component initialization to the auto-prompt dataset, and the dataset does not change. Enable the clear button by setting <code>IsClearable</code>",
21252125
"LikeMatchDescription": "In this example, type the abc string to display the viewing effect and select all matches in the collection that contain abc and have the same case",
21262126
"NoDataTipDescription": "In this example, type 567 strings because the autocomplete information center does not display custom prompt information - <code>the data you want is not found</code>",
21272127
"NoDataTip": "There is nothing",

src/BootstrapBlazor.Server/Locales/zh-CN.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2121,7 +2121,7 @@
21212121
"OnSelectedItemChangedTitle": "下拉菜单选选中回调",
21222122
"OnSelectedItemChangedIntro": "点击下拉菜单或者 <kbd>Enter</kbd> 回车时触发此回调方法",
21232123
"OnValueChanged": "Value 改变时回调方法",
2124-
"NormalDescription": "本例中请键入 123 字符串显示查看效果,自动完成组件初始化时给了自动提示数据集并且数据集无变化",
2124+
"NormalDescription": "本例中请键入 123 字符串显示查看效果,自动完成组件初始化时给了自动提示数据集并且数据集无变化,通过设置 <code>IsClearable</code> 开启清空小按钮",
21252125
"LikeMatchDescription": "本例中请键入 123 字符串显示查看效果,自动完成组件初始化时给了自动提示数据集并且数据集无变化",
21262126
"NoDataTipDescription": "本例中请键入 567 字符串由于自动完成信息中心无数据显示自定义提示信息 - <code>没有找到你想要的数据</code>",
21272127
"NoDataTip": "没有找到你想要的数据",

src/BootstrapBlazor/Components/AutoComplete/AutoComplete.razor

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
{
66
<BootstrapLabel required="@Required" for="@InputId" ShowLabelTooltip="ShowLabelTooltip" Value="@DisplayText"/>
77
}
8-
<div class="auto-complete" id="@Id">
8+
<div class="@ClassString" id="@Id">
99
<input @attributes="AdditionalAttributes" id="@InputId" class="@ClassName" autocomplete="off" type="text"
1010
data-bs-toggle="@ToggleString" data-bs-placement="@PlacementString"
1111
data-bs-offset="@OffsetString" data-bs-custom-class="@CustomClassString"
@@ -15,6 +15,10 @@
1515
placeholder="@PlaceHolder" disabled="@Disabled" @ref="FocusElement"/>
1616
<span class="form-select-append"><i class="@Icon"></i></span>
1717
<span class="form-select-append ac-loading"><i class="@LoadingIcon"></i></span>
18+
@if (GetClearable())
19+
{
20+
<span class="@ClearClassString"><i class="@ClearIcon"></i></span>
21+
}
1822
<RenderTemplate @ref="_dropdown">
1923
@RenderDropdown
2024
</RenderTemplate>

src/BootstrapBlazor/Components/AutoComplete/AutoComplete.razor.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,19 @@ public partial class AutoComplete
6868
[Parameter]
6969
public bool ShowNoDataTip { get; set; } = true;
7070

71+
/// <summary>
72+
/// Gets or sets whether the select component is clearable. Default is false.
73+
/// </summary>
74+
[Parameter]
75+
public bool IsClearable { get; set; }
76+
77+
/// <summary>
78+
/// Gets or sets the right-side clear icon. Default is fa-solid fa-angle-up.
79+
/// </summary>
80+
[Parameter]
81+
[NotNull]
82+
public string? ClearIcon { get; set; }
83+
7184
/// <summary>
7285
/// IStringLocalizer service instance
7386
/// </summary>
@@ -85,6 +98,19 @@ public partial class AutoComplete
8598
[NotNull]
8699
private RenderTemplate? _dropdown = null;
87100

101+
private string? ClassString => CssBuilder.Default("auto-complete")
102+
.AddClass("is-clearable", IsClearable)
103+
.Build();
104+
105+
/// <summary>
106+
/// Gets the clear icon class string.
107+
/// </summary>
108+
private string? ClearClassString => CssBuilder.Default("clear-icon")
109+
.AddClass($"text-{Color.ToDescriptionString()}", Color != Color.None)
110+
.AddClass($"text-success", IsValid.HasValue && IsValid.Value)
111+
.AddClass($"text-danger", IsValid.HasValue && !IsValid.Value)
112+
.Build();
113+
88114
/// <summary>
89115
/// <inheritdoc/>
90116
/// </summary>
@@ -117,6 +143,7 @@ protected override void OnParametersSet()
117143
PlaceHolder ??= Localizer[nameof(PlaceHolder)];
118144
Icon ??= IconTheme.GetIconByKey(ComponentIcons.AutoCompleteIcon);
119145
LoadingIcon ??= IconTheme.GetIconByKey(ComponentIcons.LoadingIcon);
146+
ClearIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectClearIcon);
120147
}
121148

122149
/// <summary>
@@ -125,6 +152,12 @@ protected override void OnParametersSet()
125152
/// <returns></returns>
126153
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, Value);
127154

155+
/// <summary>
156+
/// Gets whether show the clear button.
157+
/// </summary>
158+
/// <returns></returns>
159+
private bool GetClearable() => IsClearable && !IsDisabled;
160+
128161
/// <summary>
129162
/// Callback method when a candidate item is clicked
130163
/// </summary>

src/BootstrapBlazor/Components/AutoComplete/AutoComplete.razor.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ export function init(id, invoke) {
133133
EventHandler.on(document, 'click', ac.closePopover);
134134
EventHandler.on(document, 'keyup', ac.keyup);
135135
});
136+
137+
EventHandler.on(el, 'click', '.clear-icon', e => {
138+
input.value = '';
139+
invoke.invokeMethodAsync('TriggerFilter', '');
140+
});
136141
}
137142

138143
const handlerKeyup = (ac, e) => {
@@ -188,7 +193,7 @@ export function dispose(id) {
188193
Data.remove(id)
189194

190195
if (ac) {
191-
const { popover, input, menu } = ac;
196+
const { el, popover, input, menu } = ac;
192197
if (popover) {
193198
Popover.dispose(popover)
194199
if (input) {
@@ -198,6 +203,8 @@ export function dispose(id) {
198203
EventHandler.off(menu, 'click');
199204
EventHandler.off(input, 'keyup');
200205
Input.dispose(input);
206+
207+
EventHandler.off(el, 'click');
201208
}
202209

203210
const { AutoComplete } = window.BootstrapBlazor;

test/UnitTest/Components/AutoCompleteTest.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,35 @@ public void Value_Ok()
5454
Assert.Equal(2, menus.Count);
5555
}
5656

57+
[Fact]
58+
public void IsClearable_Ok()
59+
{
60+
var cut = Context.RenderComponent<AutoComplete>();
61+
Assert.DoesNotContain("clear-icon", cut.Markup);
62+
63+
cut.SetParametersAndRender(pb => pb.Add(a => a.IsClearable, true));
64+
cut.Contains("clear-icon");
65+
66+
// Color
67+
cut.SetParametersAndRender(pb => pb.Add(a => a.Color, Color.Danger));
68+
cut.Contains("clear-icon text-danger");
69+
70+
// 反射 Validate
71+
var classStringProperty = cut.Instance.GetType().GetProperty("ClearClassString", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
72+
Assert.NotNull(classStringProperty);
73+
74+
var validProperty = cut.Instance.GetType().GetProperty("IsValid", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
75+
Assert.NotNull(validProperty);
76+
77+
validProperty.SetValue(cut.Instance, true);
78+
var validClassString = classStringProperty.GetValue(cut.Instance);
79+
Assert.Equal("clear-icon text-danger text-success", validClassString);
80+
81+
validProperty.SetValue(cut.Instance, false);
82+
validClassString = classStringProperty.GetValue(cut.Instance);
83+
Assert.Equal("clear-icon text-danger text-danger", validClassString);
84+
}
85+
5786
[Fact]
5887
public void Debounce_Ok()
5988
{

0 commit comments

Comments
 (0)