DataGrid Filter Template as DropDown with Multiple Selection

Hello Radzen Team!

I'm trying to implement a custom filter in my DataGrid, using a DropDown with multiple selection. After checking out this example, managed to do some progress, but got stuck in a code generation bug.

This is the value property of the DropDown and right below are the compilation results.



dotnet: C:\Files\Projects\SolidAccessWeb\server\Pages\IdentifierList.razor(35,17): error 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'. [C:\Files\Projects\SolidAccessWeb\server\SolidAccessWeb.csproj]
C:\Files\Projects\SolidAccessWeb\server\Pages\IdentifierList.razor(35,303): error RZ9986: Component attributes do not support complex content (mixed C# and markup). Attribute: 'Value', text: '(Enum.GetValues(typeof(EnumeratorService.Type)).Cast<EnumeratorService.Type>().Select(x => new { Text = x.name, Value = x.type))}' [C:\Files\Projects\SolidAccessWeb\server\SolidAccessWeb.csproj]

Notice the bracket before the last one in the editor, it becomes a parentheses in code.

Hi @kim,

We recommend creating a page property and using a custom class instead of anonymous one. Also shouldn't you be using the Data property instead of Value? This is how our example works. Finally you can always omit the ${} from an expression if Radzen fails to generate one.

1 Like

Thanks for the feedback, you're right.

Page.Load event.
image

DropDown properties.

After fixing these, there is another error now.

It seems that value and data have different types for some reason, but not in the editor at least.
image
image

Binding the dropdown Data property to the direct value as in the example did not work either.

Have you tried implementing a multiple selection dropdown in the column filter?

You can try casting the value to List as the DropDown needs to update it (add remove values) via the ToList() method. Also since you have set the ValueProperty the selectedIdentifierTypes should contain the Value properties e.g. type: Enumerator.IdentifierTypes.Select(t => t.type). You can check how the Value of the DropDown with multiple selection is set in our demo:

 <RadzenDropDown  @bind-Value="multipleValues" 
     Multiple="true" Data="@customers" 
   TextProperty="CompanyName" ValueProperty="CustomerID"
  />
@code {
  IEnumerable<string> multipleValues = new string[] { "ALFKI", "ANATR" };
}
1 Like

Unfortunately I still get the same error.
"System.InvalidCastException: Unable to cast object of type 'System.Linq.EnumerableQuery1[System.String]' to type 'System.Collections.Generic.IEnumerable1[System.String]'."

image




image

Try converting the expression you use for the Data property to list as well (call the ToList()) method. If this doesn't help please send us your application to info@radzen.com.

1 Like

Hi @kim,

Unfortunately we were unable to run your project because of a lot of missing stuff (compilation errors). I've prepared for you an example application with our Sample database - Order Details filter by multiple products using DropDown with multiple selection in column FilterTemplate.

1 Like

Thanks a lot for this. It helped me solving the problems.

@kim or @ steveski,

I too have been struggling to make dropdown with multi selection work. I do have it working with one column in the grid with the grid's data property set to something like ${getOrderDetailsResult.Where(o => productIds.Any(p => p == o.ProductId))} but, I'm not even close to done.

I want to be able to filter multiple columns, have an AND operator between the filters (not an OR), and have each of the different filters set to default with ALL.

Problem is, while my SQL rocks, my LINQ stinks. I figured you guys have already set your grids to do what I'm trying to get, and I was hoping you wouldn't mind pasting your grid's data property LINQ stuff here, or perhaps describe how you did it if you used some other method?

Thanks much!
Stephen

Hello Stephen.

In your data property to implement the AND operator between two filters, you could write it like this:

${getOrderDetailsResult.Where(o => productIds.Contains(o.ProductId) && customerIds.Contains(o.CustomerId))}

The && in C# can be used to apply the AND operator in LINQ expressions. Also since your productIds contains only the ids (e.g. implements IEnumerable int), you could use Contains instead, because it's faster on ordered lists.

Now to have a dropdown filter with all options checked by default, you basically have to load it with all the ValueProperty items from the Data property. This depends on what your dropdown Data is, wheter if it's only the products that exist in the orders, or if it's a list with all the products. If using the later you would set productIds like so:

productIds = getProductDetailsResult.Select(p => p.Id)

Hope this helps!

Thank you very much Kim. I do appreciate the help!

I'm getting concerned about the potential penalty if I do this with many columns in the same grid. We'll see...

Hi Kim,

Everything you showed me works great, except for using the 'Contains' statement. My grids data property works with this - ${getEquipmentResult.Where(o => TypeIDs.Any(p => p == o.TypeIDFK))}

But not this - ${getEquipmentResult.Where(o => TypeIDs.Contains(o.TypeIDFK))}
Which errors: CS1929: 'IEnumerable' does not contain a definition for 'Contains' and the best extension method overload 'MemoryExtensions.Contains<int?>(ReadOnlySpan<int?>, int?)' requires a receiver of type 'ReadOnlySpan<int?>'

The original data property syntax above works, but of course I want better performance. I've tried to add various linq using directives, but no help. I certainly don't intend to bug you with my coding difficulties, but to help get me moving forward I was wondering if there's a typo in the 'Contains' syntax provided.

Thanks again,
Stephen

Hello Stephen,

The Contains method can only be used in types that implement a List. IEnumerables can do that if the value you're comparing against is the same data type as the elements it contains. In my app for example, I'm using an IEnumerable<int>.Contains(int). Comparing integers are way faster than other data types, such as strings.

I'm guessing your TypeIDs can hold <int> while TypeIDFK is a <int?>. Makes sense to allow nulls in a FK, so we'll not change that. You can, however use a null-coalescing operator ('??') and cast to another value in case your TypeIDFK is null. It would look like something like this:

${getEquipmentResult.Where(o => TypeIDs.Contains(o.TypeIDFK ?? 0))}

Here the value 0 is any value that TypeIDs will never contain, thus not being included in your final result.

Wow Kim! Yes the key / foreign key are INTs, but nulls are necessary.

Thanks to your direction, I spent the morning reading about IEnumerables, implicit casts, etc etc, and really learned a lot.

Thanks again!
Stephen

@kim Well Kim, good learning experience, but in practice the performance penalty doing this is far too high. Just filtering a couple columns this way causes the app to grind away as running hundreds of queries causing the grid to not even appear for a couple minutes. This is probably why on the demo here, a very small group of static strings is used as query params. And then there's more problems with the nulls as columns with nulls rows' won't be displayed in the result set - though I'm sure there's a way to fix that.

I'm wondering if just having some dropdowns outside of the grid for choosing the query parameters would have the same limitations? Perhaps not, because in their example (https://www.radzen.com/documentation/date-range-filter/ a much different mechanism is used, and I don't see why you couldn't plug one of these into the grid filter row as a template.

I can think of some other ways to make this work much better (in psuedocode), but with my current shortcomings with coding in this environment, I don't have enough time.

I'm going to rip all this stuff out, and do it up with a SQL Stored Procedure - Can't beat them for speed.

Best,
Slosuenos