Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions src/BootstrapBlazor.Server/Components/Samples/MultiSelects.razor
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,35 @@ private enum MultiSelectEnumFoo
</DemoBlock>

<DemoBlock Title="@Localizer["MultiSelectSearchTitle"]" Introduction="@Localizer["MultiSelectSearchIntro"]" Name="Search">
<section ignore>@((MarkupString)Localizer["MultiSelectSearchDescription"].Value)</section>
<MultiSelect Items="@Items" @bind-Value="@SelectedSearchItemsValue" ShowSearch="true" OnSearchTextChanged="@OnSearch"></MultiSelect>
<section ignore>@SelectedSearchItemsValue</section>
<ConsoleLogger @ref="Logger"></ConsoleLogger>
<section ignore>
<p>@((MarkupString)Localizer["MultiSelectSearchDescription"].Value)</p>
<div class="row g-3">
<div class="col-12 col-sm-6">
<BootstrapInputGroup>
<BootstrapInputGroupLabel DisplayText="IsFixedSearch" />
<Checkbox @bind-Value="@_isFixedSearch" />
</BootstrapInputGroup>
</div>
</div>
</section>

<div class="row g-3">
<div class="col-12 col-sm-6">
<MultiSelect Items="@Items" @bind-Value="@SelectedSearchItemsValue"
ShowSearch="true" IsFixedSearch="_isFixedSearch" OnSearchTextChanged="@OnSearch">
</MultiSelect>
</div>
<div class="col-12 col-sm-6">
<MultiSelect Items="@LongItems" @bind-Value="@SelectedMaxItemsValue"
ShowSearch="true" IsFixedSearch="_isFixedSearch">
</MultiSelect>
</div>
</div>

<section ignore>
<p>@SelectedSearchItemsValue</p>
<ConsoleLogger @ref="Logger"></ConsoleLogger>
</section>
</DemoBlock>

<DemoBlock Title="@Localizer["MultiSelectGroupTitle"]" Introduction="@Localizer["MultiSelectGroupIntro"]" Name="Group">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ private enum MultiSelectEnumFoo

private string? _editString;

private bool _isFixedSearch;

private async Task<SelectedItem> OnEditCallback(string value)
{
await Task.Delay(100);
Expand Down
8 changes: 6 additions & 2 deletions src/BootstrapBlazor.Server/Components/Samples/Selects.razor
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,14 @@
</section>
<div class="row g-3">
<div class="col-12 col-sm-6">
<Select TValue="string" Items="Items" ShowSearch="true" IsClearable="_isShowSearchClearable" IsFixedSearch="_isFixedSearch" />
<Select TValue="string" Items="Items" ShowSearch="true"
IsClearable="_isShowSearchClearable" IsFixedSearch="_isFixedSearch">
</Select>
</div>
<div class="col-12 col-sm-6">
<Select TValue="string" Items="StringItems" ShowSearch="true" IsClearable="_isShowSearchClearable" IsFixedSearch="_isFixedSearch" />
<Select TValue="string" Items="StringItems" ShowSearch="true"
IsClearable="_isShowSearchClearable" IsFixedSearch="_isFixedSearch">
</Select>
</div>
</div>
</DemoBlock>
Expand Down
98 changes: 53 additions & 45 deletions src/BootstrapBlazor/Components/Select/MultiSelect.razor
Original file line number Diff line number Diff line change
Expand Up @@ -48,63 +48,71 @@
<span class="@AppendClassString"><i class="@DropdownIcon"></i></span>
}
</div>
<div class="dropdown-menu">
<div class="@SearchClassString">
<input type="text" class="form-control search-text" autocomplete="off" value="@SearchText" aria-label="search" />
<i class="@SearchIconString"></i>
<i class="@SearchLoadingIconString"></i>
</div>
@if (ShowToolbar)
<div class="@DropdownMenuClassString">
@if (ShowSearch)
{
<div class="toolbar">
@if (ShowDefaultButtons)
{
<DynamicElement TagName="button" type="button" class="btn" OnClick="SelectAll">@SelectAllText</DynamicElement>
<DynamicElement TagName="button" type="button" class="btn" OnClick="InvertSelect">@ReverseSelectText</DynamicElement>
<DynamicElement TagName="button" type="button" class="btn" OnClick="Clear">@ClearText</DynamicElement>
}
@ButtonTemplate
<div class="dropdown-menu-search">
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search" />
<i class="@SearchIconString"></i>
<i class="@SearchLoadingIconString"></i>
</div>
}
@foreach (var itemGroup in Rows.GroupBy(i => i.GroupName))
@if (Rows.Count == 0)
{
if (!string.IsNullOrEmpty(itemGroup.Key))
{
if (GroupItemTemplate != null)
{
@GroupItemTemplate(itemGroup.Key)
}
else
<div class="dropdown-item">@NoSearchDataText</div>
}
else
{
<div class="dropdown-menu-body">
@if (ShowToolbar)
{
<Divider Text="@itemGroup.Key" />
}
}
@foreach (var item in itemGroup)
{
<DynamicElement OnClick="() => ToggleRow(item.Value)" TriggerClick="@CheckCanTrigger(item)" class="@GetItemClassString(item)">
<div class="multi-select-item">
<div class="form-check">
<input class="form-check-input" type="checkbox" disabled="@CheckCanSelect(item)" checked="@GetCheckedString(item)" />
</div>
@if (ItemTemplate != null)
<div class="toolbar">
@if (ShowDefaultButtons)
{
@ItemTemplate(item)
<DynamicElement TagName="button" type="button" class="btn" OnClick="SelectAll">@SelectAllText</DynamicElement>
<DynamicElement TagName="button" type="button" class="btn" OnClick="InvertSelect">@ReverseSelectText</DynamicElement>
<DynamicElement TagName="button" type="button" class="btn" OnClick="Clear">@ClearText</DynamicElement>
}
else if (IsMarkupString)
@ButtonTemplate
</div>
}
@foreach (var itemGroup in Rows.GroupBy(i => i.GroupName))
{
if (!string.IsNullOrEmpty(itemGroup.Key))
{
if (GroupItemTemplate != null)
{
@((MarkupString)item.Text)
@GroupItemTemplate(itemGroup.Key)
}
else
{
<span>@item.Text</span>
<Divider Text="@itemGroup.Key" />
}
</div>
</DynamicElement>
}
}
@if (Rows.Count == 0)
{
<div class="dropdown-item">@NoSearchDataText</div>
}
@foreach (var item in itemGroup)
{
<DynamicElement OnClick="() => ToggleRow(item.Value)" TriggerClick="@CheckCanTrigger(item)" class="@GetItemClassString(item)">
<div class="multi-select-item">
<div class="form-check">
<input class="form-check-input" type="checkbox" disabled="@CheckCanSelect(item)" checked="@GetCheckedString(item)" />
</div>
@if (ItemTemplate != null)
{
@ItemTemplate(item)
}
else if (IsMarkupString)
{
@((MarkupString)item.Text)
}
else
{
<span>@item.Text</span>
}
</div>
</DynamicElement>
}
}
</div>
}
</div>
</div>
7 changes: 0 additions & 7 deletions src/BootstrapBlazor/Components/Select/MultiSelect.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,6 @@ public partial class MultiSelect<TValue>
.AddClass("d-none", SelectedItems.Count != 0)
.Build();

private string? SearchClassString => CssBuilder.Default("search")
.AddClass("show", ShowSearch)
.Build();

/// <summary>
/// 获得 SearchLoadingIcon 图标字符串
/// </summary>
private string? SearchLoadingIconString => CssBuilder.Default("icon searching-icon")
.AddClass(SearchLoadingIcon)
.Build();
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Components/Select/Select.razor
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
@if (ShowSearch)
{
<div class="dropdown-menu-search">
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search">
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search" />
<i class="@SearchIconString"></i>
<i class="@SearchLoadingIconString"></i>
</div>
Expand Down
23 changes: 4 additions & 19 deletions src/BootstrapBlazor/Components/Select/Select.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ public partial class Select<TValue> : ISelect, ILookup
.AddClass(SearchLoadingIcon)
.Build();

private string? DropdownMenuClassString => CssBuilder.Default("dropdown-menu")
.AddClass("is-fixed-search", ShowSearch && IsFixedSearch)
.Build();

private readonly List<SelectedItem> _children = [];

private string? ScrollIntoViewBehaviorString => ScrollIntoViewBehavior == ScrollIntoViewBehavior.Smooth ? null : ScrollIntoViewBehavior.ToDescriptionString();
Expand All @@ -68,12 +64,6 @@ public partial class Select<TValue> : ISelect, ILookup
[Parameter]
public Func<string, IEnumerable<SelectedItem>>? OnSearchTextChanged { get; set; }

/// <summary>
/// Gets or sets whether the search bar in the dropdown is fixed. Default is false.
/// </summary>
[Parameter]
public bool IsFixedSearch { get; set; }

/// <summary>
/// Gets or sets whether the select component is editable. Default is false.
/// </summary>
Expand Down Expand Up @@ -106,7 +96,7 @@ public partial class Select<TValue> : ISelect, ILookup
public RenderFragment<SelectedItem?>? DisplayTemplate { get; set; }

/// <summary>
/// Gets or sets whether virtual scrolling is enabled. Default is false. Note: When virtual scrolling is enabled, <see cref="SelectBase{TValue}.ShowSearch"/>, <see cref="PopoverSelectBase{TValue}.IsPopover"/>, and <seealso cref="IsFixedSearch"/> are not supported. Set <see cref="DefaultVirtualizeItemText"/> when setting initial values.
/// Gets or sets whether virtual scrolling is enabled. Default is false.
/// </summary>
[Parameter]
public bool IsVirtualize { get; set; }
Expand Down Expand Up @@ -397,13 +387,6 @@ private async ValueTask<ItemsProviderResult<SelectedItem>> LoadItems(ItemsProvid
int GetCountByTotal() => TotalCount == 0 ? request.Count : Math.Min(request.Count, TotalCount - request.StartIndex);
}

private async Task SearchTextChanged(string val)
{
_itemsCache = null;
SearchText = val;
await RefreshVirtualizeElement();
}

private async Task RefreshVirtualizeElement()
{
if (IsVirtualize && OnQueryAsync != null)
Expand Down Expand Up @@ -473,7 +456,9 @@ public async Task ConfirmSelectedItem(int index)
[JSInvokable]
public async Task TriggerOnSearch(string searchText)
{
await SearchTextChanged(searchText);
_itemsCache = null;
SearchText = searchText;
await RefreshVirtualizeElement();
StateHasChanged();
}

Expand Down
13 changes: 13 additions & 0 deletions src/BootstrapBlazor/Components/Select/SelectBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ public abstract class SelectBase<TValue> : PopoverSelectBase<TValue>
[Parameter]
public bool ShowSearch { get; set; }

/// <summary>
/// Gets or sets whether the search bar in the dropdown is fixed. Default is false.
/// </summary>
[Parameter]
public bool IsFixedSearch { get; set; }

/// <summary>
/// Gets or sets the search icon.
/// </summary>
Expand Down Expand Up @@ -115,6 +121,13 @@ public abstract class SelectBase<TValue> : PopoverSelectBase<TValue>
.AddClass($"text-danger", IsValid.HasValue && !IsValid.Value)
.Build();

/// <summary>
/// Gets the dropdown menu class string.
/// </summary>
protected string? DropdownMenuClassString => CssBuilder.Default("dropdown-menu")
.AddClass("is-fixed-search", ShowSearch && IsFixedSearch)
.Build();

/// <summary>
/// <inheritdoc/>
/// </summary>
Expand Down
23 changes: 13 additions & 10 deletions src/BootstrapBlazor/Components/SelectGeneric/SelectGeneric.razor
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,15 @@
{
<span class="@ClearClassString" @onclick="OnClearValue"><i class="@ClearIcon"></i></span>
}
<div class="dropdown-menu">
<div class="@SearchClassString">
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search">
<i class="@SearchIconString"></i>
<i class="@SearchLoadingIconString"></i>
</div>
<div class="@DropdownMenuClassString">
@if (ShowSearch)
{
<div class="dropdown-menu-search">
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search" />
<i class="@SearchIconString"></i>
<i class="@SearchLoadingIconString"></i>
</div>
}
@if (IsVirtualize)
{
<div class="dropdown-virtual">
Expand All @@ -49,6 +52,10 @@
}
</div>
}
else if (Rows.Count == 0)
{
<div class="dropdown-item">@NoSearchDataText</div>
}
else
{
@foreach (var itemGroup in Rows.GroupBy(i => i.GroupName))
Expand All @@ -69,10 +76,6 @@
@RenderRow(item)
}
}
@if (Rows.Count == 0)
{
<div class="dropdown-item">@NoSearchDataText</div>
}
}
</div>
@if (!IsPopover)
Expand Down
Loading