Skip to content

Commit

Permalink
feat(SelectObject): add IsClearable parameter (#5077)
Browse files Browse the repository at this point in the history
* feat: 增加 IsClearable 参数

* doc: 更新示例

* chore: bump version 9.2.7-beta02

* test: 更新单元测试

Co-Authored-By: ice6 <[email protected]>
  • Loading branch information
ArgoZhang and ice6 authored Jan 9, 2025
1 parent 1e0338b commit 9864a4f
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
<h4>@Localizer["Intro"]</h4>

<DemoBlock Title="@Localizer["NormalTitle"]" Introduction="@Localizer["NormalIntro"]" Name="Normal">
<SelectObject @bind-Value="_value" GetTextCallback="GetTextCallback">
<section ignore>
@((MarkupString)Localizer["NormalDesc"].Value)
</section>
<SelectObject @bind-Value="_value" GetTextCallback="GetTextCallback" IsClearable>
<ListView TItem="ListViews.Product" Items="@Products" OnListViewItemClick="item => OnListViewItemClick(item, context)">
<BodyTemplate Context="value">
<Card>
Expand Down
1 change: 1 addition & 0 deletions src/BootstrapBlazor.Server/Locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -6599,6 +6599,7 @@
"Intro": "Dropdown boxes are used to display the selection requirements for complex types for any component",
"NormalTitle": "Basic usage",
"NormalIntro": "Use built in <code>ListView</code> component to select images",
"NormalDesc": "You can use <code>IsClearable</code> to control whether to display the clear button. The default value is <code>false</code>",
"MinWidthTitle": "Min-Width",
"MinWidthIntro": "Change the minimum width of the dropdown box by setting the <code>DropdownMinWidth</code> value",
"HeightTitle": "Height",
Expand Down
1 change: 1 addition & 0 deletions src/BootstrapBlazor.Server/Locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -6599,6 +6599,7 @@
"Intro": "下拉框为任意组件用于展示复杂类型的选择需求",
"NormalTitle": "基本功能",
"NormalIntro": "内置 <code>ListView</code> 组件选择图片",
"NormalDesc": "可通过 <code>IsClearable</code> 控制是否显示清除小按钮,默认值 <code>false</code>",
"MinWidthTitle": "设置最小宽度",
"MinWidthIntro": "通过设置 <code>DropdownMinWidth</code> 值,来改变下拉框最小宽度",
"HeightTitle": "设置高度",
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>9.2.7-beta01</Version>
<Version>9.2.7-beta02</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 4 additions & 0 deletions src/BootstrapBlazor/Components/Select/SelectObject.razor
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
<span class="@AppendClassString"><i class="@DropdownIcon"></i></span>
}
</div>
@if (GetClearable())
{
<span class="@ClearClassString" @onclick="OnClearValue"><i class="@ClearIcon"></i></span>
}
<div class="dropdown-menu dropdown-object" style="@GetStyleString">
@ChildContent(_context)
</div>
Expand Down
40 changes: 40 additions & 0 deletions src/BootstrapBlazor/Components/Select/SelectObject.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ public partial class SelectObject<TItem>
[NotNull]
public string? DropdownIcon { get; set; }

/// <summary>
/// 获得/设置 是否可清除 默认 false
/// </summary>
[Parameter]
public bool IsClearable { get; set; }

/// <summary>
/// 获得/设置 右侧清除图标 默认 fa-solid fa-angle-up
/// </summary>
[Parameter]
[NotNull]
public string? ClearIcon { get; set; }

/// <summary>
/// 获得/设置 下拉列表内容模板
/// </summary>
Expand All @@ -66,6 +79,7 @@ public partial class SelectObject<TItem>
/// </summary>
private string? ClassName => CssBuilder.Default("select select-object dropdown")
.AddClass("disabled", IsDisabled)
.AddClass("cls", IsClearable)
.AddClassFromAttributes(AdditionalAttributes)
.Build();

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

private string? ClearClassString => CssBuilder.Default("clear-icon")
.AddClass($"text-{Color.ToDescriptionString()}", Color != Color.None)
.AddClass($"text-success", IsValid.HasValue && IsValid.Value)
.AddClass($"text-danger", IsValid.HasValue && !IsValid.Value)
.Build();

/// <summary>
/// 获得 PlaceHolder 属性
/// </summary>
Expand All @@ -107,6 +127,12 @@ public partial class SelectObject<TItem>
[Parameter]
public RenderFragment<TItem>? Template { get; set; }

/// <summary>
/// 获得/设置 清除文本内容 OnClear 回调方法 默认 null
/// </summary>
[Parameter]
public Func<Task>? OnClearAsync { get; set; }

[Inject]
[NotNull]
private IStringLocalizer<Select<TItem>>? Localizer { get; set; }
Expand Down Expand Up @@ -151,6 +177,7 @@ protected override void OnParametersSet()

PlaceHolder ??= Localizer[nameof(PlaceHolder)];
DropdownIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectDropdownIcon);
ClearIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectClearIcon);
}

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

private bool GetClearable() => IsClearable && !IsDisabled;

/// <summary>
/// 获得 Text 显示文字
/// </summary>
Expand All @@ -170,4 +199,15 @@ protected override void OnParametersSet()
/// </summary>
/// <returns></returns>
public Task CloseAsync() => InvokeVoidAsync("close", Id);

private async Task OnClearValue()
{
if (OnClearAsync != null)
{
await OnClearAsync();
}

Value = default;
await CloseAsync();
}
}
29 changes: 29 additions & 0 deletions test/UnitTest/Components/SelectObjectTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ public async Task Value_Ok()
await cut.InvokeAsync(() => item.Click());
Assert.NotNull(v);
Assert.Equal(url, v.ImageUrl);

var isClear = false;
cut.SetParametersAndRender(pb =>
{
pb.Add(a => a.IsClearable, true);
pb.Add(a => a.OnClearAsync, () =>
{
isClear = true;
return Task.CompletedTask;
});
});
Assert.Contains("clear-icon", cut.Markup);

var span = cut.Find(".clear-icon");
await cut.InvokeAsync(() => span.Click());
var input = cut.Find(".form-select");
Assert.Null(input.GetAttribute("value"));
Assert.True(isClear);
}

[Fact]
Expand All @@ -61,8 +79,12 @@ public void Color_Ok()
{
pb.AddContent(0, "test");
});
pb.Add(a => a.IsClearable, true);
});
cut.Contains("border-danger");

var span = cut.Find(".clear-icon");
Assert.True(span.ClassList.Contains("text-danger"));
}

[Fact]
Expand Down Expand Up @@ -182,6 +204,7 @@ public async Task Validate_Ok()
builder.Add(a => a.Model, model);
builder.AddChildContent<SelectObject<string>>(pb =>
{
pb.Add(a => a.IsClearable, true);
pb.Add(a => a.Value, model.Name);
pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(model, "Name", typeof(string)));
pb.Add(a => a.OnValueChanged, v =>
Expand All @@ -205,6 +228,9 @@ await cut.InvokeAsync(() =>
});
Assert.True(valid);

var span = cut.Find(".clear-icon");
Assert.True(span.ClassList.Contains("text-success"));

model.Name = null;
var table = cut.FindComponent<SelectObject<string>>();
table.SetParametersAndRender();
Expand All @@ -214,6 +240,9 @@ await cut.InvokeAsync(() =>
form.Submit();
});
Assert.True(invalid);

span = cut.Find(".clear-icon");
Assert.True(span.ClassList.Contains("text-danger"));
}

class Product
Expand Down

0 comments on commit 9864a4f

Please sign in to comment.