mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-07-08 18:16:08 +00:00
Add AutoApplyCheckBoxListFilter to apply CheckBoxList filters on selection (#2554)
This commit is contained in:
@@ -3489,6 +3489,94 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains("Nothing to display", component.Markup);
|
||||
}
|
||||
|
||||
private sealed class AutoApplyItem
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public int Code { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_AutoApplyCheckBoxListFilter_FiltersOnSelectionWithoutApply()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var data = new[]
|
||||
{
|
||||
new AutoApplyItem { Name = "A", Code = 1 },
|
||||
new AutoApplyItem { Name = "B", Code = 2 },
|
||||
new AutoApplyItem { Name = "C", Code = 1 },
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<AutoApplyItem>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<AutoApplyItem>>(p => p.Data, data);
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.CheckBoxList);
|
||||
parameterBuilder.Add<bool>(p => p.AutoApplyCheckBoxListFilter, true);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<AutoApplyItem>));
|
||||
builder.AddAttribute(1, "Property", nameof(AutoApplyItem.Code));
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
// Open the Code filter popup (the filter icon toggles via @onmousedown=ToggleFilter)
|
||||
component.Find("button.rz-grid-filter-icon").MouseDown();
|
||||
|
||||
// Wait for the listbox to load its filter values asynchronously.
|
||||
component.WaitForAssertion(() => Assert.NotEmpty(component.FindAll(".rz-multiselect-item")), TimeSpan.FromSeconds(3));
|
||||
|
||||
// Apply button must NOT be present in auto-apply mode
|
||||
Assert.Empty(component.FindAll("button.rz-apply-filter"));
|
||||
|
||||
// Select the option for Code == 1 in the listbox and confirm the grid filters immediately.
|
||||
// Find the listbox item whose text is "1" and click it.
|
||||
var item = component.FindAll(".rz-multiselect-item")
|
||||
.FirstOrDefault(i => i.TextContent.Trim() == "1");
|
||||
Assert.NotNull(item);
|
||||
item!.Click();
|
||||
|
||||
var grid = component.Instance;
|
||||
var codes = ((System.Collections.IEnumerable)grid.View).Cast<AutoApplyItem>().Select(x => x.Code).Distinct().ToArray();
|
||||
Assert.Equal(new[] { 1 }, codes);
|
||||
|
||||
// The popup must stay open after auto-apply so additional options can be selected.
|
||||
// Applying the filter with closePopup:false means no popup-closing JS interop runs;
|
||||
// closePopup:true would invoke Radzen.closePopup / Radzen.closeAllPopups.
|
||||
Assert.DoesNotContain(ctx.JSInterop.Invocations,
|
||||
i => i.Identifier.Contains("close", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_CheckBoxListFilter_RendersApplyButton_WhenAutoApplyOff()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var data = new[] { new AutoApplyItem { Name = "A", Code = 1 } };
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<AutoApplyItem>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<AutoApplyItem>>(p => p.Data, data);
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.CheckBoxList);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<AutoApplyItem>));
|
||||
builder.AddAttribute(1, "Property", nameof(AutoApplyItem.Code));
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
component.Find("button.rz-grid-filter-icon").MouseDown();
|
||||
|
||||
Assert.NotEmpty(component.FindAll("button.rz-apply-filter"));
|
||||
}
|
||||
|
||||
private sealed class TrackingEnumerable<T> : IEnumerable<T>
|
||||
{
|
||||
private readonly IEnumerable<T> _source;
|
||||
|
||||
@@ -1611,6 +1611,14 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool AllowFiltering { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether CheckBoxList column filters are applied immediately as options are
|
||||
/// selected, instead of requiring the filter popup's Apply button. Default is false.
|
||||
/// </summary>
|
||||
/// <value>True to apply CheckBoxList filters on each selection change; otherwise false.</value>
|
||||
[Parameter]
|
||||
public bool AutoApplyCheckBoxListFilter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether column resizing is allowed.
|
||||
/// </summary>
|
||||
|
||||
@@ -188,7 +188,10 @@
|
||||
{
|
||||
<div class="rz-grid-filter-buttons">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Base" class="rz-clear-filter" Click="@ClearFilter" Text=@Grid.ClearFilterText title="@Grid.ClearFilterText" />
|
||||
<RadzenButton onmousedown="@getBlur()" ButtonStyle="ButtonStyle.Primary" class="rz-apply-filter" form="@($"{Column.GetColumnPopupID()}-form")" ButtonType="ButtonType.Submit" Text=@Grid.ApplyFilterText title="@Grid.ApplyFilterText" />
|
||||
@if (!(Grid.AutoApplyCheckBoxListFilter && filterMode == FilterMode.CheckBoxList))
|
||||
{
|
||||
<RadzenButton onmousedown="@getBlur()" ButtonStyle="ButtonStyle.Primary" class="rz-apply-filter" form="@($"{Column.GetColumnPopupID()}-form")" ButtonType="ButtonType.Submit" Text=@Grid.ApplyFilterText title="@Grid.ApplyFilterText" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</Popup>
|
||||
@@ -350,43 +353,52 @@ else
|
||||
return string.IsNullOrWhiteSpace(Column.HeaderTooltip) ? null : Column.HeaderTooltip;
|
||||
}
|
||||
|
||||
void ListBoxChange(object args)
|
||||
async Task ListBoxChange(object args)
|
||||
{
|
||||
hasPendingCheckBoxFilter = true;
|
||||
|
||||
if (args is not IEnumerable enumerable)
|
||||
{
|
||||
pendingCheckBoxFilterValue = null;
|
||||
return;
|
||||
}
|
||||
|
||||
Type? propertyType = null;
|
||||
|
||||
if (Column.Property != Column.FilterProperty && !string.IsNullOrEmpty(Column.FilterProperty))
|
||||
{
|
||||
var collectionType = PropertyAccess.GetPropertyType(typeof(TItem), Column.Property);
|
||||
if (collectionType != null && collectionType.IsGenericType)
|
||||
{
|
||||
var itemType = collectionType.GenericTypeArguments.FirstOrDefault();
|
||||
if(itemType != null)
|
||||
{
|
||||
propertyType = PropertyAccess.GetPropertyType(itemType, Column.FilterProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyType = PropertyAccess.GetPropertyType(typeof(TItem), Column.GetFilterProperty());
|
||||
Type? propertyType = null;
|
||||
|
||||
if (Column.Property != Column.FilterProperty && !string.IsNullOrEmpty(Column.FilterProperty))
|
||||
{
|
||||
var collectionType = PropertyAccess.GetPropertyType(typeof(TItem), Column.Property);
|
||||
if (collectionType != null && collectionType.IsGenericType)
|
||||
{
|
||||
var itemType = collectionType.GenericTypeArguments.FirstOrDefault();
|
||||
if(itemType != null)
|
||||
{
|
||||
propertyType = PropertyAccess.GetPropertyType(itemType, Column.FilterProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyType = PropertyAccess.GetPropertyType(typeof(TItem), Column.GetFilterProperty());
|
||||
}
|
||||
|
||||
if (propertyType == null)
|
||||
{
|
||||
propertyType = Column.FilterPropertyType;
|
||||
}
|
||||
|
||||
pendingCheckBoxFilterValue = enumerable.Cast<object>().Any()
|
||||
? propertyType != null ? QueryableExtension.ToList(enumerable.AsQueryable().Cast(propertyType)) : enumerable
|
||||
: null;
|
||||
}
|
||||
|
||||
if (propertyType == null)
|
||||
if (Grid.AutoApplyCheckBoxListFilter)
|
||||
{
|
||||
propertyType = Column.FilterPropertyType;
|
||||
Column.SetFilterValue(pendingCheckBoxFilterValue);
|
||||
hasPendingCheckBoxFilter = false;
|
||||
pendingCheckBoxFilterValue = null;
|
||||
await Grid.ApplyFilter(Column, false);
|
||||
}
|
||||
|
||||
pendingCheckBoxFilterValue = enumerable.Cast<object>().Any()
|
||||
? propertyType != null ? QueryableExtension.ToList(enumerable.AsQueryable().Cast(propertyType)) : enumerable
|
||||
: null;
|
||||
}
|
||||
|
||||
string getFilterOpen()
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
<RadzenDataGrid AllowFiltering="true" FilterMode="FilterMode.CheckBoxList" AutoApplyCheckBoxListFilter="true"
|
||||
AllowPaging="true" PageSize="5" Data="@orders" ColumnWidth="200px">
|
||||
<Columns>
|
||||
<RadzenDataGridColumn Property="@nameof(Order.Reference)" Title="Reference" />
|
||||
<RadzenDataGridColumn Property="@nameof(Order.Status)" Title="Status" />
|
||||
</Columns>
|
||||
</RadzenDataGrid>
|
||||
|
||||
@code {
|
||||
class Order
|
||||
{
|
||||
public string Reference { get; set; } = "";
|
||||
public string Status { get; set; } = "";
|
||||
}
|
||||
|
||||
readonly List<Order> orders = new()
|
||||
{
|
||||
new Order { Reference = "ORD-001", Status = "Open" },
|
||||
new Order { Reference = "ORD-002", Status = "Shipped" },
|
||||
new Order { Reference = "ORD-003", Status = "Closed" },
|
||||
new Order { Reference = "ORD-004", Status = "Open" },
|
||||
new Order { Reference = "ORD-005", Status = "Shipped" },
|
||||
new Order { Reference = "ORD-006", Status = "Closed" }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
@page "/datagrid-checkboxlist-auto-apply-filter"
|
||||
|
||||
<RadzenText TextStyle="TextStyle.H2" TagName="TagName.H1" class="rz-pt-8">
|
||||
DataGrid <strong>CheckBoxList Filter Auto-Apply</strong>
|
||||
</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P" class="rz-pb-4">
|
||||
Set AutoApplyCheckBoxListFilter on the grid to apply CheckBoxList column filters immediately as
|
||||
options are selected, without the filter popup's Apply button.
|
||||
</RadzenText>
|
||||
|
||||
<RadzenExample ComponentName="DataGrid" Example="DataGridCheckBoxListAutoApplyFilter">
|
||||
<DataGridCheckBoxListAutoApplyFilter />
|
||||
</RadzenExample>
|
||||
@@ -611,6 +611,14 @@ namespace RadzenBlazorDemos
|
||||
Tags = new [] { "filter", "excel", "grid", "datagrid", "table", "menu", "checkbox", "list" }
|
||||
},
|
||||
new Example
|
||||
{
|
||||
Name = "CheckBoxList Auto-Apply",
|
||||
Path = "datagrid-checkboxlist-auto-apply-filter",
|
||||
Title = "Blazor DataGrid - CheckBoxList Filter Auto-Apply | Free UI Components by Radzen",
|
||||
Description = "Apply CheckBoxList column filters immediately as options are selected, without the Apply button.",
|
||||
Tags = new [] { "checkboxlist", "auto", "apply", "filter", "filtering", "datagrid", "table", "dataview" }
|
||||
},
|
||||
new Example
|
||||
{
|
||||
Name = "CheckBoxList with OData",
|
||||
Path = "datagrid-checkboxlist-filter-odata",
|
||||
|
||||
Reference in New Issue
Block a user