Skip to content

Commit 9864a4f

Browse files
ArgoZhangice6
andauthored
feat(SelectObject): add IsClearable parameter (#5077)
* feat: 增加 IsClearable 参数 * doc: 更新示例 * chore: bump version 9.2.7-beta02 * test: 更新单元测试 Co-Authored-By: ice6 <[email protected]>
1 parent 1e0338b commit 9864a4f

File tree

7 files changed

+80
-2
lines changed

7 files changed

+80
-2
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
<h4>@Localizer["Intro"]</h4>
88

99
<DemoBlock Title="@Localizer["NormalTitle"]" Introduction="@Localizer["NormalIntro"]" Name="Normal">
10-
<SelectObject @bind-Value="_value" GetTextCallback="GetTextCallback">
10+
<section ignore>
11+
@((MarkupString)Localizer["NormalDesc"].Value)
12+
</section>
13+
<SelectObject @bind-Value="_value" GetTextCallback="GetTextCallback" IsClearable>
1114
<ListView TItem="ListViews.Product" Items="@Products" OnListViewItemClick="item => OnListViewItemClick(item, context)">
1215
<BodyTemplate Context="value">
1316
<Card>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6599,6 +6599,7 @@
65996599
"Intro": "Dropdown boxes are used to display the selection requirements for complex types for any component",
66006600
"NormalTitle": "Basic usage",
66016601
"NormalIntro": "Use built in <code>ListView</code> component to select images",
6602+
"NormalDesc": "You can use <code>IsClearable</code> to control whether to display the clear button. The default value is <code>false</code>",
66026603
"MinWidthTitle": "Min-Width",
66036604
"MinWidthIntro": "Change the minimum width of the dropdown box by setting the <code>DropdownMinWidth</code> value",
66046605
"HeightTitle": "Height",

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6599,6 +6599,7 @@
65996599
"Intro": "下拉框为任意组件用于展示复杂类型的选择需求",
66006600
"NormalTitle": "基本功能",
66016601
"NormalIntro": "内置 <code>ListView</code> 组件选择图片",
6602+
"NormalDesc": "可通过 <code>IsClearable</code> 控制是否显示清除小按钮,默认值 <code>false</code>",
66026603
"MinWidthTitle": "设置最小宽度",
66036604
"MinWidthIntro": "通过设置 <code>DropdownMinWidth</code> 值,来改变下拉框最小宽度",
66046605
"HeightTitle": "设置高度",

src/BootstrapBlazor/BootstrapBlazor.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>9.2.7-beta01</Version>
4+
<Version>9.2.7-beta02</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Components/Select/SelectObject.razor

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
<span class="@AppendClassString"><i class="@DropdownIcon"></i></span>
3232
}
3333
</div>
34+
@if (GetClearable())
35+
{
36+
<span class="@ClearClassString" @onclick="OnClearValue"><i class="@ClearIcon"></i></span>
37+
}
3438
<div class="dropdown-menu dropdown-object" style="@GetStyleString">
3539
@ChildContent(_context)
3640
</div>

src/BootstrapBlazor/Components/Select/SelectObject.razor.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ public partial class SelectObject<TItem>
4646
[NotNull]
4747
public string? DropdownIcon { get; set; }
4848

49+
/// <summary>
50+
/// 获得/设置 是否可清除 默认 false
51+
/// </summary>
52+
[Parameter]
53+
public bool IsClearable { get; set; }
54+
55+
/// <summary>
56+
/// 获得/设置 右侧清除图标 默认 fa-solid fa-angle-up
57+
/// </summary>
58+
[Parameter]
59+
[NotNull]
60+
public string? ClearIcon { get; set; }
61+
4962
/// <summary>
5063
/// 获得/设置 下拉列表内容模板
5164
/// </summary>
@@ -66,6 +79,7 @@ public partial class SelectObject<TItem>
6679
/// </summary>
6780
private string? ClassName => CssBuilder.Default("select select-object dropdown")
6881
.AddClass("disabled", IsDisabled)
82+
.AddClass("cls", IsClearable)
6983
.AddClassFromAttributes(AdditionalAttributes)
7084
.Build();
7185

@@ -89,6 +103,12 @@ public partial class SelectObject<TItem>
89103
.AddClass($"text-danger", IsValid.HasValue && !IsValid.Value)
90104
.Build();
91105

106+
private string? ClearClassString => CssBuilder.Default("clear-icon")
107+
.AddClass($"text-{Color.ToDescriptionString()}", Color != Color.None)
108+
.AddClass($"text-success", IsValid.HasValue && IsValid.Value)
109+
.AddClass($"text-danger", IsValid.HasValue && !IsValid.Value)
110+
.Build();
111+
92112
/// <summary>
93113
/// 获得 PlaceHolder 属性
94114
/// </summary>
@@ -107,6 +127,12 @@ public partial class SelectObject<TItem>
107127
[Parameter]
108128
public RenderFragment<TItem>? Template { get; set; }
109129

130+
/// <summary>
131+
/// 获得/设置 清除文本内容 OnClear 回调方法 默认 null
132+
/// </summary>
133+
[Parameter]
134+
public Func<Task>? OnClearAsync { get; set; }
135+
110136
[Inject]
111137
[NotNull]
112138
private IStringLocalizer<Select<TItem>>? Localizer { get; set; }
@@ -151,6 +177,7 @@ protected override void OnParametersSet()
151177

152178
PlaceHolder ??= Localizer[nameof(PlaceHolder)];
153179
DropdownIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectDropdownIcon);
180+
ClearIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectClearIcon);
154181
}
155182

156183
/// <summary>
@@ -159,6 +186,8 @@ protected override void OnParametersSet()
159186
/// <returns></returns>
160187
protected override bool IsRequired() => ValidateForm != null;
161188

189+
private bool GetClearable() => IsClearable && !IsDisabled;
190+
162191
/// <summary>
163192
/// 获得 Text 显示文字
164193
/// </summary>
@@ -170,4 +199,15 @@ protected override void OnParametersSet()
170199
/// </summary>
171200
/// <returns></returns>
172201
public Task CloseAsync() => InvokeVoidAsync("close", Id);
202+
203+
private async Task OnClearValue()
204+
{
205+
if (OnClearAsync != null)
206+
{
207+
await OnClearAsync();
208+
}
209+
210+
Value = default;
211+
await CloseAsync();
212+
}
173213
}

test/UnitTest/Components/SelectObjectTest.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,24 @@ public async Task Value_Ok()
4848
await cut.InvokeAsync(() => item.Click());
4949
Assert.NotNull(v);
5050
Assert.Equal(url, v.ImageUrl);
51+
52+
var isClear = false;
53+
cut.SetParametersAndRender(pb =>
54+
{
55+
pb.Add(a => a.IsClearable, true);
56+
pb.Add(a => a.OnClearAsync, () =>
57+
{
58+
isClear = true;
59+
return Task.CompletedTask;
60+
});
61+
});
62+
Assert.Contains("clear-icon", cut.Markup);
63+
64+
var span = cut.Find(".clear-icon");
65+
await cut.InvokeAsync(() => span.Click());
66+
var input = cut.Find(".form-select");
67+
Assert.Null(input.GetAttribute("value"));
68+
Assert.True(isClear);
5169
}
5270

5371
[Fact]
@@ -61,8 +79,12 @@ public void Color_Ok()
6179
{
6280
pb.AddContent(0, "test");
6381
});
82+
pb.Add(a => a.IsClearable, true);
6483
});
6584
cut.Contains("border-danger");
85+
86+
var span = cut.Find(".clear-icon");
87+
Assert.True(span.ClassList.Contains("text-danger"));
6688
}
6789

6890
[Fact]
@@ -182,6 +204,7 @@ public async Task Validate_Ok()
182204
builder.Add(a => a.Model, model);
183205
builder.AddChildContent<SelectObject<string>>(pb =>
184206
{
207+
pb.Add(a => a.IsClearable, true);
185208
pb.Add(a => a.Value, model.Name);
186209
pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(model, "Name", typeof(string)));
187210
pb.Add(a => a.OnValueChanged, v =>
@@ -205,6 +228,9 @@ await cut.InvokeAsync(() =>
205228
});
206229
Assert.True(valid);
207230

231+
var span = cut.Find(".clear-icon");
232+
Assert.True(span.ClassList.Contains("text-success"));
233+
208234
model.Name = null;
209235
var table = cut.FindComponent<SelectObject<string>>();
210236
table.SetParametersAndRender();
@@ -214,6 +240,9 @@ await cut.InvokeAsync(() =>
214240
form.Submit();
215241
});
216242
Assert.True(invalid);
243+
244+
span = cut.Find(".clear-icon");
245+
Assert.True(span.ClassList.Contains("text-danger"));
217246
}
218247

219248
class Product

0 commit comments

Comments
 (0)