Skip to content

Commit 6113b85

Browse files
authored
feat(SelectTable): add IsClearable parameter (#5074)
* feat: 增加 IsClearable 参数 * style: 更新样式 * doc: 更新示例 * chore: bump version 9.2.7-beta01 * test: 增加单元测试 * test: 更新单元测试
1 parent 68ddec2 commit 6113b85

File tree

8 files changed

+118
-19
lines changed

8 files changed

+118
-19
lines changed

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

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

88
<DemoBlock Title="@Localizer["NormalTitle"]" Introduction="@Localizer["NormalIntro"]" Name="Normal">
9-
<SelectTable TItem="Foo" @bind-Value="@_foo" OnQueryAsync="OnQueryAsync" GetTextCallback="@GetTextCallback" TableMinWidth="300">
9+
<section ignore>
10+
@((MarkupString)Localizer["NormalDesc"].Value)
11+
</section>
12+
<SelectTable TItem="Foo" @bind-Value="@_foo" OnQueryAsync="OnQueryAsync" GetTextCallback="@GetTextCallback" TableMinWidth="300" IsClearable>
1013
<TableColumns>
1114
<TableColumn @bind-Field="@context.Name"></TableColumn>
1215
<TableColumn @bind-Field="@context.Address"></TableColumn>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6567,6 +6567,7 @@
65676567
"Intro": "The dropdown box is a table used to display the selection requirements for complex types",
65686568
"NormalTitle": "Basic usage",
65696569
"NormalIntro": "Suitable for candidates with a relatively large amount of information, presenting information using <code>Table</code>",
6570+
"NormalDesc": "You can use <code>IsClearable</code> to control whether to display the clear button. The default value is <code>false</code>",
65706571
"ColorTitle": "Color",
65716572
"ColorIntro": "Change component border color by setting <code>Color</code>",
65726573
"IsDisabledTitle": "Disabled",

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6567,6 +6567,7 @@
65676567
"Intro": "下拉框为表格用于展示复杂类型的选择需求",
65686568
"NormalTitle": "基本功能",
65696569
"NormalIntro": "适用于候选项信息量比较大,用 <code>Table</code> 呈现信息量",
6570+
"NormalDesc": "可通过 <code>IsClearable</code> 控制是否显示清除小按钮,默认值 <code>false</code>",
65706571
"ColorTitle": "颜色",
65716572
"ColorIntro": "通过设置 <code>Color</code> 改变组件边框颜色",
65726573
"IsDisabledTitle": "禁用",

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.6</Version>
4+
<Version>9.2.7-beta01</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Components/Select/Select.razor.scss

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -147,25 +147,27 @@
147147
transform: rotate(0);
148148
}
149149

150-
.select .clear-icon {
151-
position: absolute;
152-
height: 100%;
153-
width: var(--bb-select-append-width);
154-
right: 0;
155-
top: 0;
156-
color: var(--bb-select-append-color);
157-
align-items: center;
158-
justify-content: center;
159-
cursor: pointer;
160-
display: none;
161-
}
150+
.select {
151+
.clear-icon {
152+
position: absolute;
153+
height: 100%;
154+
width: var(--bb-select-append-width);
155+
right: 0;
156+
top: 0;
157+
color: var(--bb-select-append-color);
158+
align-items: center;
159+
justify-content: center;
160+
cursor: pointer;
161+
display: none;
162+
}
162163

163-
.select:hover .clear-icon {
164-
display: flex;
165-
}
164+
&:hover .clear-icon {
165+
display: flex;
166+
}
166167

167-
.select.cls:hover .form-select-append {
168-
display: none;
168+
&.cls:hover .form-select-append {
169+
display: none;
170+
}
169171
}
170172

171173
.form-select.is-valid:focus,

src/BootstrapBlazor/Components/Select/SelectTable.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
<CascadingValue Value="this" IsFixed="true">
3539
@TableColumns?.Invoke(new TItem())
3640
</CascadingValue>

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ namespace BootstrapBlazor.Components;
6161
[NotNull]
6262
public string? DropdownIcon { get; set; }
6363

64+
/// <summary>
65+
/// 获得/设置 是否可清除 默认 false
66+
/// </summary>
67+
[Parameter]
68+
public bool IsClearable { get; set; }
69+
6470
/// <summary>
6571
/// 获得/设置 IIconTheme 服务实例
6672
/// </summary>
@@ -78,6 +84,7 @@ namespace BootstrapBlazor.Components;
7884
/// </summary>
7985
private string? ClassName => CssBuilder.Default("select select-table dropdown")
8086
.AddClass("disabled", IsDisabled)
87+
.AddClass("cls", IsClearable)
8188
.AddClassFromAttributes(AdditionalAttributes)
8289
.Build();
8390

@@ -101,6 +108,15 @@ namespace BootstrapBlazor.Components;
101108
.AddClass($"text-danger", IsValid.HasValue && !IsValid.Value)
102109
.Build();
103110

111+
private bool GetClearable() => IsClearable && !IsDisabled;
112+
113+
/// <summary>
114+
/// 获得/设置 右侧清除图标 默认 fa-solid fa-angle-up
115+
/// </summary>
116+
[Parameter]
117+
[NotNull]
118+
public string? ClearIcon { get; set; }
119+
104120
/// <summary>
105121
/// 获得 PlaceHolder 属性
106122
/// </summary>
@@ -174,6 +190,12 @@ namespace BootstrapBlazor.Components;
174190
[Parameter]
175191
public bool AutoGenerateColumns { get; set; }
176192

193+
/// <summary>
194+
/// 获得/设置 清除文本内容 OnClear 回调方法 默认 null
195+
/// </summary>
196+
[Parameter]
197+
public Func<Task>? OnClearAsync { get; set; }
198+
177199
[Inject]
178200
[NotNull]
179201
private IStringLocalizer<Select<TItem>>? Localizer { get; set; }
@@ -191,6 +213,12 @@ namespace BootstrapBlazor.Components;
191213

192214
private string GetStyleString => $"height: {Height}px;";
193215

216+
private string? ClearClassString => CssBuilder.Default("clear-icon")
217+
.AddClass($"text-{Color.ToDescriptionString()}", Color != Color.None)
218+
.AddClass($"text-success", IsValid.HasValue && IsValid.Value)
219+
.AddClass($"text-danger", IsValid.HasValue && !IsValid.Value)
220+
.Build();
221+
194222
/// <summary>
195223
/// <inheritdoc/>
196224
/// </summary>
@@ -220,6 +248,7 @@ protected override void OnParametersSet()
220248

221249
PlaceHolder ??= Localizer[nameof(PlaceHolder)];
222250
DropdownIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectDropdownIcon);
251+
ClearIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectClearIcon);
223252
}
224253

225254
/// <summary>
@@ -239,4 +268,14 @@ private async Task OnClickRowCallback(TItem item)
239268
CurrentValue = item;
240269
await InvokeVoidAsync("close", Id);
241270
}
271+
272+
private async Task OnClearValue()
273+
{
274+
if (OnClearAsync != null)
275+
{
276+
await OnClearAsync();
277+
}
278+
279+
await OnClickRowCallback(default!);
280+
}
242281
}

test/UnitTest/Components/SelectTableTest.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,44 @@ public void Items_Ok()
3636
});
3737
}
3838

39+
[Fact]
40+
public async Task IsClearable_Ok()
41+
{
42+
var localizer = Context.Services.GetRequiredService<IStringLocalizer<Foo>>();
43+
var items = Foo.GenerateFoo(localizer, 4);
44+
var cut = Context.RenderComponent<BootstrapBlazorRoot>(pb =>
45+
{
46+
pb.AddChildContent<SelectTable<Foo>>(pb =>
47+
{
48+
pb.Add(a => a.OnQueryAsync, options => OnFilterQueryAsync(options, items));
49+
pb.Add(a => a.GetTextCallback, foo => foo.Name);
50+
});
51+
});
52+
var table = cut.FindComponent<SelectTable<Foo>>();
53+
Assert.DoesNotContain("clear-icon", table.Markup);
54+
55+
var isClear = false;
56+
table.SetParametersAndRender(pb =>
57+
{
58+
pb.Add(a => a.IsClearable, true);
59+
pb.Add(a => a.Value, items[0]);
60+
pb.Add(a => a.OnClearAsync, () =>
61+
{
62+
isClear = true;
63+
return Task.CompletedTask;
64+
});
65+
});
66+
Assert.Contains("clear-icon", table.Markup);
67+
var input = table.Find(".form-select");
68+
Assert.Equal("张三 0001", input.GetAttribute("value"));
69+
70+
var span = table.Find(".clear-icon");
71+
await table.InvokeAsync(() => span.Click());
72+
input = table.Find(".form-select");
73+
Assert.Null(input.GetAttribute("value"));
74+
Assert.True(isClear);
75+
}
76+
3977
[Fact]
4078
public void TableMinWidth_Ok()
4179
{
@@ -65,9 +103,13 @@ public void Color_Ok()
65103
pb.Add(a => a.Color, Color.Danger);
66104
pb.Add(a => a.GetTextCallback, foo => foo.Name);
67105
pb.Add(a => a.OnQueryAsync, options => OnFilterQueryAsync(options, items));
106+
pb.Add(a => a.IsClearable, true);
68107
});
69108
});
70109
cut.Contains("border-danger");
110+
111+
var span = cut.Find(".clear-icon");
112+
Assert.True(span.ClassList.Contains("text-danger"));
71113
}
72114

73115
[Fact]
@@ -271,6 +313,7 @@ public async Task Validate_Ok()
271313
builder.Add(a => a.Model, model);
272314
builder.AddChildContent<SelectTable<Foo>>(pb =>
273315
{
316+
pb.Add(a => a.IsClearable, true);
274317
pb.Add(a => a.Value, model.Foo);
275318
pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(model, "Foo", typeof(Foo)));
276319
pb.Add(a => a.OnValueChanged, v =>
@@ -302,6 +345,9 @@ await cut.InvokeAsync(() =>
302345
});
303346
Assert.True(valid);
304347

348+
var span = cut.Find(".clear-icon");
349+
Assert.True(span.ClassList.Contains("text-success"));
350+
305351
model.Foo = null;
306352
var table = cut.FindComponent<SelectTable<Foo>>();
307353
table.SetParametersAndRender();
@@ -311,6 +357,9 @@ await cut.InvokeAsync(() =>
311357
form.Submit();
312358
});
313359
Assert.True(invalid);
360+
361+
span = cut.Find(".clear-icon");
362+
Assert.True(span.ClassList.Contains("text-danger"));
314363
}
315364

316365
[Fact]

0 commit comments

Comments
 (0)