Data Grid Custom Filter with ListBox

I have followed your demo here Blazor DataGrid - Custom Filtering | Free UI Components by Radzen and when you clear the filters the ListBox still shows a selected Item, but the grid does clear the filters. If I switch it out to a Drop down and have a @ref to said dropdown I can get it cleared by setting the SelectedLocations = null, call StateHasChanged() then call Reset on the Drop down. This does not work on a listbox. The demo site will keep items selected as well. Just calling reset on Dropdown does not clear selected items.

<FilterTemplate Context="column">
    <RadzenStack class="rz-grid-filter">
        <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Stretch" JustifyContent="JustifyContent.SpaceBetween">
            <RadzenText class="rz-grid-filter-label">Filter</RadzenText>
        </RadzenStack>
        <RadzenListBox @ref="SelectedLocationLb" @bind-Value="@SelectedLocations" Style="width:100%; height: 225px;"
                       Multiple="true"  AllowClear="true" AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
                       Change="@(() => OnSelectedLocationChange(column))" Data="@AllLocations" class="rz-clear-filters" />
        <RadzenDropDown @ref="SelectedLocationDd" @bind-Value="@SelectedLocations" class="rz-clear-filters" Style="width:100%"
                        Multiple="true" AllowClear="true" AllowFiltering="true" OpenOnFocus="true" ClearSearchAfterSelection="true" MaxSelectedLabels="8" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
                        Change="@(() => MultiFilterSelectionChanged(SelectedLocationDd))" Data="@AllLocations" />
        <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.SpaceBetween" Style="padding: 6px;" class="rz-grid-filter-buttons">
            <RadzenButton Text="Clear" Click="@(() => FilterClear(column))" class="rz-button rz-button-md rz-variant-filled rz-base rz-shade-default rz-clear-filter" />
            <RadzenButton Text="Close" Click="@(() => FilterClose(column))" class="rz-button rz-button-md rz-variant-filled rz-primary rz-shade-default" />
        </RadzenStack>
    </RadzenStack>
</FilterTemplate>
protected RadzenDropDown<List<string>> SelectedLocationDd;

private async Task FilterClear(RadzenDataGridColumn<LotViewDto> column)
{
    if (SelectedLocations != null)
    {
        SelectedLocations = null;
        StateHasChanged();        
        SelectedLocationDd.Reset();
    }
    await column.CloseFilter();
}

Thanks,

Nate

Can you provide runnable code demonstrating your case to test and debug it?

If you go to your sites page from above, use the second demo, Paste the code below in there and run it, select a dropdown value; you will see the data grid change. Click the clear button and then reopen the filter, the Dropdown will have nothing selected but the list box will still have a selected value.

@if (employees == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <RadzenText TextStyle="TextStyle.H6" TagName="TagName.H2" class="rz-my-6">Custom filtering template with Custom Command</RadzenText>
    <RadzenDataGrid Render="@OnRender" Style="height:400px;" AllowVirtualization="true" @ref="grid" Data=@employees FilterMode="FilterMode.Advanced"
                    AllowFiltering="true" AllowPaging="false" AllowSorting="true" ColumnWidth="200px">
        <Columns>
            <RadzenDataGridColumn Property="ID" Title="ID" FilterValue="@idValue">
            </RadzenDataGridColumn>
            <RadzenDataGridColumn Title="Customer" Property="CompanyName">
            </RadzenDataGridColumn>
            <RadzenDataGridColumn Title="Hire Date" Property="HireDate.Date" FormatString="{0:d}"
                                  FilterValue="@hireDate?.Date">
            </RadzenDataGridColumn>
            <RadzenDataGridColumn Title="Work Status" Property="WorkStatus" Type="typeof(IEnumerable<string>)" Sortable=true
                                  FilterValue="@selectedWorkStatus" FilterOperator="FilterOperator.Custom" LogicalFilterOperator="@workStatusOperator">
                <FilterTemplate Context="column">
                    <div class="rz-grid-filter">
                        <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Stretch" JustifyContent="JustifyContent.SpaceBetween">
                            <span class="rz-grid-filter-label">Filter</span>
                        </RadzenStack>
                        <RadzenListBox AllowClear="true" @bind-Value=@selectedWorkStatus Multiple="true" AllowSelectAll=true Style="width:100%; height:200px;"
                                       Change="@(()=>OnSelectedWorkStatusChange(column))" Data=@workStatuses />

                        <RadzenDropDown @ref="SelectedLocationDd" @bind-Value="@selectedWorkStatus" class="rz-clear-filters" Style="width:100%"
                Multiple="true" AllowClear="true" AllowFiltering="true" OpenOnFocus="true" ClearSearchAfterSelection="true" MaxSelectedLabels="8" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
                Change="@(() => OnSelectedWorkStatusChange(column))" Data="@workStatuses" />

                        <div class="rz-grid-filter-buttons">
                            <RadzenButton ButtonStyle="ButtonStyle.Secondary" Text="Clear" Click="@(() => WorkStatusFilterClear(column))" />
                            <RadzenButton ButtonStyle="ButtonStyle.Primary" Text="Close" Click="@(() => WorkStatusFilterClose(column))" />
                        </div>
                    </div>
                </FilterTemplate>
            </RadzenDataGridColumn>
            <RadzenDataGridColumn Property="@nameof(Employee.TitleOfCourtesy)" Title="Title Of Courtesy" 
                FilterValue="@currentTOC">
                <FilterTemplate>
                    <RadzenListBox @bind-Value="@currentTOC" TextProperty="Text" ValueProperty="Value" Style="width:100%;" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "filter by title of courtesy" }})"
                                    Change=@OnSelectedTOCChange
                                    Data="@(Enum.GetValues(typeof(TitleOfCourtesy)).Cast<TitleOfCourtesy?>().Select(t => new { Text = $"{t}", Value = t == TitleOfCourtesy.All ? null : t }))" />
                </FilterTemplate>
            </RadzenDataGridColumn>
        </Columns>
    </RadzenDataGrid>
}


@code {
    RadzenDataGrid<Employee> grid;
    int? idValue = null;
    DateTime? hireDate = null;
    TitleOfCourtesy? currentTOC;
    List<string> selectedWorkStatus;
    protected RadzenDropDown<List<string>> SelectedLocationDd;
    string whereExpression;

    public LogicalFilterOperator workStatusOperator { get; set; } = LogicalFilterOperator.Or;

    List<string> companyNames = new List<string> {"Vins et alcools Chevalier", "Toms Spezialitäten", "Hanari Carnes", "Richter Supermarkt", "Wellington Importadora", "Centro comercial Moctezuma" };
    List<string> workStatuses = new List<string> { "Office", "Remote", "Temporary", "Permanent" };
    public enum TitleOfCourtesy
    {
        Ms,
        Mr,
        All = -1
    }

    public class Employee
    {
        public int ID { get; set; }
        public string CompanyName { get; set; }
        public DateTime HireDate { get; set; }
        public TitleOfCourtesy TitleOfCourtesy { get; set; }
        public string WorkStatus { get; set; }
    }

    void OnSelectedTOCChange(object value)
    {
        if (currentTOC == TitleOfCourtesy.All)
        {
            currentTOC = null;
        }
    }

    IEnumerable<Employee> employees; 

    protected override async Task OnInitializedAsync()
    {
        employees = await Task.FromResult(Enumerable.Range(0, 60).Select(i =>
            new Employee
            {
                ID = i,
                CompanyName = companyNames[i % 6],
                HireDate = DateTime.Now.AddMonths(-i),
                TitleOfCourtesy = i % 2 == 1 ? TitleOfCourtesy.Mr : TitleOfCourtesy.Ms,
                    WorkStatus = $"{(i < 20 ? "Office" : i >= 20 && i < 40 ? "Remote" : "Office, Remote")} {(i < 12 ? ", Temporary" : i >= 12 && i < 30 ? ", Permanent" : i > 30 && i < 44 ? ", Temporary" : ", Permanent")}"
            }).AsQueryable());
    }

    private async Task WorkStatusFilterClear(RadzenDataGridColumn<Employee> column)
    {
        if(selectedWorkStatus != null)
        {
            selectedWorkStatus = null;            
            StateHasChanged();
            SelectedLocationDd.Reset();            
        }
        await column.CloseFilter();
    }

    private async Task WorkStatusFilterClose(RadzenDataGridColumn<Employee> column)
    {
        await column.CloseFilter();
    }

    async Task OnSelectedWorkStatusChange(RadzenDataGridColumn<Employee> column)
    {
        var createWhereExpression = new List<string>();

        if (selectedWorkStatus?.Any() == true)
        {
            whereExpression = string.Join($" {Enum.GetName(typeof(LogicalFilterOperator), workStatusOperator).ToLowerInvariant()} ",
                selectedWorkStatus.Select(s => $"it.WorkStatus.Contains(\"{s}\")"));
        }
        else
        {
            whereExpression = null;
            selectedWorkStatus = null;
        }

        await column.SetCustomFilterExpressionAsync(whereExpression);
    }

    void OnRender(DataGridRenderEventArgs<Employee> args)
    {
        if (args.FirstRender)
        {
            args.Grid.Sorts.Add(new SortDescriptor() { Property = "CompanyName", SortOrder = SortOrder.Ascending });
            args.Grid.Sorts.Add(new SortDescriptor() { Property = "TitleOfCourtesy", SortOrder = SortOrder.Ascending });
        }
    }
}

@enchev I think the issue is that the ListBox does not reset like the Dropdown. Any time I call reset on the drop down after setting the list of objects null the selected values will be reset, just not on the list box with checkboxes.

Thanks @Nate! We found the bug and fix will be published before the end of the week.

1 Like