How to filter a datagridColumn with a multiple selection dropdown

Hi everyone,

I have hard time trying to figure how to filter a datagrid column with a multiple selection dropdown.

I have this component :

        <RadzenDataGridColumn  TItem="DossierView" Property="DemandeEvaluationPCH.Libelle" Title="Demande Evaluation PCH" TextAlign="TextAlign.Center" Width="150px" FilterValue="DemandesEvaluationFilter"  FilterOperator="FilterOperator.Equals">
                        <HeaderTemplate>
                            Demande <br> evaluation PCH
                        </HeaderTemplate>
                        <EditTemplate Context="dossier">
                            <RadzenDropDown @bind-Value="dossier.DemandeEvaluationPCH" Data="@demandesEvaluationPCH">
                                <Template>
                                    @context.Libelle
                                </Template>
                            </RadzenDropDown>
                        </EditTemplate>
                        <FilterTemplate>
                            <RadzenDropDown Multiple="true" @ref="DemandeEvaluationPCHDropDown" @bind-value="DemandesEvaluationFilter" TValue="string" ValueProperty="DemandeEvaluationPCH.Libelle" Data="@(demandesEvaluationPCH)" TextProperty="DemandeEvaluationPCH.Libelle" AllowClear="true"/>
                        </FilterTemplate>
                    </RadzenDataGridColumn>

As in this demo : Blazor DropDown | a free UI component by Radzen my bind-Value is an Enumerable

but there is a problem because my TValue must be a string and therefore I have an error saying that my value can't convert from IEnumerable to string

Did someone already went through this?

Thanks in advance

Pierre

Multiple selection requires IEnumerable as there are many values. You can't have TValue as a string.

1 Like

Yesthat's what i thought, but if i TValue as IEnumerable then my FilterValue is An IEnumerable where as my datagrid column property is a string so i get the same error

This demo demonstrates filtering with multiple selection: Blazor DataGrid custom filtering

Thanks a lot, I've tried following the demo but the filter is not working (i can select but it don't actually filter anything)
And more i have an error

warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
      Unhandled exception rendering component: Object reference not set to an instance of an object.
      System.NullReferenceException: Object reference not set to an instance of an object.
         at Radzen.DropDownBase`1.SelectAll()
         at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
fail: Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost[111]
      Unhandled exception in circuit 'Zr7jFnIV9-MhQULuENFLaHXl9RG1GfzBoUVp6G8M_-c'.
      System.NullReferenceException: Object reference not set to an instance of an object.
         at Radzen.DropDownBase`1.SelectAll()
         at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

when i try to select all cases.

Here is my code

                        FilterValue="@DemandesEvaluationFilter"  FilterOperator="FilterOperator.Contains" LogicalFilterOperator="LogicalFilterOperator.Or" Type="typeof(IEnumerable<string>)">
                        <HeaderTemplate>
                            Demande <br> evaluation PCH
                        </HeaderTemplate>
                        <EditTemplate Context="dossier">
                            <RadzenDropDown @bind-Value="dossier.DemandeEvaluationPCH" Data="@demandesEvaluationPCH">
                                <Template>
                                    @context.Libelle
                                </Template>
                            </RadzenDropDown>
                        </EditTemplate>
                        <FilterTemplate>
                            <RadzenDropDown Multiple="true" AllowClear="true" @ref=@DemandeEvaluationPCHDropDown @bind-value=@DemandesEvaluationFilter
                                 TValue="IEnumerable<string>" ValueProperty="DemandeEvaluationPCH.Libelle" TextProperty="DemandeEvaluationPCH.Libelle" Data="@(demandesEvaluationPCH)"/>
                        </FilterTemplate>
                    </RadzenDataGridColumn>

    private List<DemandeEvaluationPCH>? demandesEvaluationPCH = new();
    private RadzenDropDown<IEnumerable<string>> DemandeEvaluationPCHDropDown = new();
    private IEnumerable<string>? DemandesEvaluationFilter = null;

Do you have any idea?

Thanks again for your help

The code from our demo is this:

<RadzenDataGridColumn TItem="Employee" Title="Customer" Property="CompanyName" Type="typeof(IEnumerable<string>)"  FilterValue="@selectedCompanyNames" FilterOperator="FilterOperator.Contains" LogicalFilterOperator="LogicalFilterOperator.Or">
   <FilterTemplate>
        <RadzenDropDown @bind-Value=@selectedCompanyNames Style="width:100%;"
            Change=@OnSelectedCompanyNamesChange Data="@(companyNames)" AllowClear="true" Multiple="true" />
    </FilterTemplate>
</RadzenDataGridColumn>

The DropDown doesn't have TValue set in our example which could be the problem - try removing it.

1 Like

I had already tried that but i have this error when i trie to remove TValue

RZ10001|The type of component 'RadzenDropDown' cannot be inferred based on the values provided. Consider specifying the type arguments directly using the following attributes: 'TValue'.

That's strange - our demo works without TValue.

Anyway that's the only difference I can find right now. Not sure why it doesn't work for you. Can you reproduce this problem by modifying our demo source code?

Yes of course,

I think it comes from the fact that my property is a sub-object, so i modified the employee class to contain a Company class that has just a name, and then i set ValueProperty and TextProperty on the dropdown, and now the filter crash when i select all, and it doesnt work when i select one of the company

@page "/test"
@using System.Linq.Dynamic.Core

<h1>DataGrid custom Column FilterTemplate</h1>

<p>This page demonstrates how to define custom DataGrid column filter template.</p>

    @if (employees == null)
    {
        <p><em>Loading...</em></p>
    }
    else
    {
        <h3>Custom filtering template with IQueryable binding</h3>
         <RadzenDataGrid @ref="grid" Data=@employees FilterMode="FilterMode.Simple" AllowFiltering="true" AllowPaging="true" AllowSorting="true" TItem="Employee" ColumnWidth="200px">
            <Columns>
                <RadzenDataGridColumn TItem="Employee" Property="ID" Title="ID" />
                <RadzenDataGridColumn TItem="Employee" Title="Customer" Property="Company.Name" Type="typeof(IEnumerable<string>)" 
                        FilterValue="@selectedCompanyNames" FilterOperator="FilterOperator.Contains" LogicalFilterOperator="LogicalFilterOperator.Or">
                    <FilterTemplate>
                        <RadzenDropDown @bind-Value=@selectedCompanyNames Style="width:100%;" ValueProperty="Company.Name" TextProperty="Company.Name"
                            Change=@OnSelectedCompanyNamesChange Data="@(companies)" AllowClear="true" Multiple="true" />
                    </FilterTemplate>
                </RadzenDataGridColumn>
                <RadzenDataGridColumn TItem="Employee" Property="TitleOfCourtesy" Title="Title Of Courtesy" 
                    FilterValue="@currentTOC">
                    <FilterTemplate>
                        <RadzenDropDown @bind-Value="@currentTOC" TextProperty="Text" ValueProperty="Value" Style="width:100%;"
                                        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;

    TitleOfCourtesy? currentTOC;
    IEnumerable<string> selectedCompanyNames;

    List<Company> companies = new();
    List<string> companyNames = new List<string> {"Vins et alcools Chevalier", "Toms Spezialitäten", "Hanari Carnes", "Richter Supermarkt", "Wellington Importadora", "Centro comercial Moctezuma" };

    public enum TitleOfCourtesy
    {
        Ms,
        Mr,
        All = -1
    }

    public class Company
    {
        public string Name {get; set;}
    }

    public class Employee
    {
        public int ID { get; set; }
        public Company Company { get; set; }
        public TitleOfCourtesy TitleOfCourtesy { get; set; }
    }

    void OnSelectedCompanyNamesChange(object value)
    {
        if (selectedCompanyNames != null && !selectedCompanyNames.Any())
        {
            selectedCompanyNames = null;  
        }
    }

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

    IEnumerable<Employee> employees; 

    protected override async Task OnInitializedAsync()
    {
        Company companie1 = new Company
        {
            Name = "Vins et alcools Chevalier"
        };
        Company companie2 = new Company
        {
            Name = "Toms Spezialitäten"
        };

        companies.Add(companie1);
        companies.Add(companie2);

        employees = await Task.FromResult(Enumerable.Range(0, 2).Select(i =>
            new Employee
            {
                ID = i,
                Company = i == 0? companie1 : companie2,
                TitleOfCourtesy = i < 5 ? TitleOfCourtesy.Mr : TitleOfCourtesy.Ms
            }).AsQueryable());
    }
}

This will work if you configure the DropDown like this (TextProperty and ValueProperty are set to "Name"):

 <RadzenDropDown @bind-Value=@selectedCompanyNames 
    Style="width:100%;" ValueProperty="Name" TextProperty="Name"
    Change=@OnSelectedCompanyNamesChange Data="@(companies)" AllowClear="true" Multiple="true" />
1 Like

Thanks a lot!
I wouldn't have been able to figure this out alone!

ValueProperty and TextProperty should be property names of the underlying data item (in your case Company). Setting them to "Company.Name" is invalid as Company does not have a Company property of its own.

1 Like

Sorry but now i have an error clearing the filter with the grid.Reset() method

With the modified demo this is the code

@page "/test"
@using System.Linq.Dynamic.Core

<h1>DataGrid custom Column FilterTemplate</h1>

<p>This page demonstrates how to define custom DataGrid column filter template.</p>

    @if (employees == null)
    {
        <p><em>Loading...</em></p>
    }
    else
    {
        <RadzenButton Click=ClearFilter> TEST </RadzenButton>
        <h3>Custom filtering template with IQueryable binding</h3>
         <RadzenDataGrid @ref="grid" Data=@employees FilterMode="FilterMode.Simple" AllowFiltering="true" AllowPaging="true" AllowSorting="true" TItem="Employee" ColumnWidth="200px">
            <Columns>
                <RadzenDataGridColumn TItem="Employee" Property="ID" Title="ID" />
                <RadzenDataGridColumn TItem="Employee" Title="Customer" Property="Company.Name" Type="typeof(IEnumerable<string>)" 
                        FilterValue="@selectedCompanyNames" FilterOperator="FilterOperator.Contains" LogicalFilterOperator="LogicalFilterOperator.Or">
                    <FilterTemplate>
                        <RadzenDropDown @bind-Value=@selectedCompanyNames Style="width:100%;" ValueProperty="Name" TextProperty="Name"
                            Change=@OnSelectedCompanyNamesChange Data="@(companies)" AllowClear="true" Multiple="true" />
                    </FilterTemplate>
                </RadzenDataGridColumn>
                <RadzenDataGridColumn TItem="Employee" Property="TitleOfCourtesy" Title="Title Of Courtesy" 
                    FilterValue="@currentTOC">
                    <FilterTemplate>
                        <RadzenDropDown @bind-Value="@currentTOC" TextProperty="Text" ValueProperty="Value" Style="width:100%;"
                                        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;

    TitleOfCourtesy? currentTOC;
    IEnumerable<string> selectedCompanyNames;

    List<Company> companies = new();
    List<string> companyNames = new List<string> {"Vins et alcools Chevalier", "Toms Spezialitäten", "Hanari Carnes", "Richter Supermarkt", "Wellington Importadora", "Centro comercial Moctezuma" };

    public enum TitleOfCourtesy
    {
        Ms,
        Mr,
        All = -1
    }

    public class Company
    {
        public string Name {get; set;}
    }

    public class Employee
    {
        public int ID { get; set; }
        public Company Company { get; set; }
        public TitleOfCourtesy TitleOfCourtesy { get; set; }
    }

    void ClearFilter()
    {
        grid.Reset();
    }
    void OnSelectedCompanyNamesChange(object value)
    {
        if (selectedCompanyNames != null && !selectedCompanyNames.Any())
        {
            selectedCompanyNames = null;  
        }
    }

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

    IEnumerable<Employee> employees; 

    protected override async Task OnInitializedAsync()
    {
        Company companie1 = new Company
        {
            Name = "Vins et alcools Chevalier"
        };
        Company companie2 = new Company
        {
            Name = "Toms Spezialitäten"
        };

        companies.Add(companie1);
        companies.Add(companie2);

        employees = await Task.FromResult(Enumerable.Range(0, 2).Select(i =>
            new Employee
            {
                ID = i,
                Company = i == 0? companie1 : companie2,
                TitleOfCourtesy = i < 5 ? TitleOfCourtesy.Mr : TitleOfCourtesy.Ms
            }).AsQueryable());
    }
}

and this is the error

warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
      Unhandled exception rendering component: Operator '=' incompatible with operand types 'String' and 'EnumerableQuery`1'
      Operator '=' incompatible with operand types 'String' and 'EnumerableQuery`1' (at index 19)
fail: Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost[111]
      Unhandled exception in circuit 'yFEdKo1jDv1oGqfkViZLuRZ8NKv3jB2FTOdaRiMah6M'.
      Operator '=' incompatible with operand types 'String' and 'EnumerableQuery`1' (at index 19)
warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
      Unhandled exception rendering component: Cannot access a disposed object.
      System.ObjectDisposedException: Cannot access a disposed object.
         at Microsoft.AspNetCore.Components.RenderTree.ArrayBuilder`1.ThrowObjectDisposedException()
         at Microsoft.AspNetCore.Components.RenderTree.ArrayBuilder`1.GrowBuffer(Int32 desiredCapacity)
         at Microsoft.AspNetCore.Components.ParameterView.CaptureSnapshot(ArrayBuilder`1 builder)
         at Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.UpdateRetainedChildComponent(DiffContext& diffContext, Int32 oldComponentIndex, Int32 newComponentIndex)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& diffContext, Int32 oldFrameIndex, Int32 newFrameIndex)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& diffContext, Int32 oldFrameIndex, Int32 newFrameIndex)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& diffContext, Int32 oldFrameIndex, Int32 newFrameIndex)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange`1 oldTree, ArrayRange`1 newTree)
         at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException)
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
fail: Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost[111]
      Unhandled exception in circuit 'yFEdKo1jDv1oGqfkViZLuRZ8NKv3jB2FTOdaRiMah6M'.
      System.ObjectDisposedException: Cannot access a disposed object.
         at Microsoft.AspNetCore.Components.RenderTree.ArrayBuilder`1.ThrowObjectDisposedException()
         at Microsoft.AspNetCore.Components.RenderTree.ArrayBuilder`1.GrowBuffer(Int32 desiredCapacity)
         at Microsoft.AspNetCore.Components.ParameterView.CaptureSnapshot(ArrayBuilder`1 builder)
         at Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.UpdateRetainedChildComponent(DiffContext& diffContext, Int32 oldComponentIndex, Int32 newComponentIndex)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& diffContext, Int32 oldFrameIndex, Int32 newFrameIndex)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& diffContext, Int32 oldFrameIndex, Int32 newFrameIndex)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& diffContext, Int32 oldFrameIndex, Int32 newFrameIndex)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
         at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange`1 oldTree, ArrayRange`1 newTree)
         at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException)
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

Thanks again

We were able to reproduce this and we will do our best to include fix in our next update early next week.

1 Like