Column Filter Menu in Blazor Grid
- 9 minutes to read
The column filter menu displays a dropdown with all unique values within a column and allows users to filter column data. A size grip in the corner of the filter menu allows users to change the menu’s width and height.
Use the following properties to display the filter menu buttons in the column headers:
- DxGrid.FilterMenuButtonDisplayMode
- Specifies when the Grid displays filter menu buttons in column headers.
- DxGridDataColumn.FilterMenuButtonDisplayMode
- Specifies when the column displays the filter menu button.
Note
The Grid cannot create filter item lists for columns associated with certain data types (for instance, arrays and images). If you do not implement a filter menu template for such a column, the column filter menu displays the following text instead of filter items: “No filters are available for this column”.
Once you apply a filter to a column, other filter menus hide values that do not match the specified filter criteria. Hold down Shift and click a filter button to display all values. Focus a column header and press Alt+Arrow Down or Shift+Alt+Arrow Down to open the filter menu.
When a user clicks the menu’s Clear button, the filter menu changes the current operator type to Default
.
Customize Filter Items
When a user clicks a filter menu button, the Grid creates a list of default filter items. The table below lists settings that you can specify in the EditSettings render fragment:
Editor Settings | Applicable Data Types | Supported Properties |
---|---|---|
Any data type | ||
Any data type | CheckedDisplayText, ValueChecked, UncheckedDisplayText, ValueUnchecked, IndeterminateDisplayText, ValueIndeterminate |
The following code snippet uses the DxComboBoxSettings object to specify the text used to display the Category column’s filter menu items:
<DxGrid Data="GridData"
FilterMenuButtonDisplayMode="GridFilterMenuButtonDisplayMode.Always"
@* ... *@
VirtualScrollingEnabled="true">
<Columns>
<DxGridDataColumn FieldName="OrderDate" Width="140px" />
<DxGridDataColumn FieldName="ProductName" MinWidth="100" />
<DxGridDataColumn FieldName="CategoryId" Caption="Category" Width="130px">
<EditSettings>
<DxComboBoxSettings Data="Categories" ValueFieldName="CategoryId" TextFieldName="CategoryName" />
</EditSettings>
</DxGridDataColumn>
<DxGridDataColumn FieldName="UnitPrice" DisplayFormat="c2" Width="140px" />
<DxGridDataColumn FieldName="Quantity" Width="110px" />
<DxGridDataColumn FieldName="Discount" DisplayFormat="p0" Width="110px" />
<DxGridDataColumn FieldName="Total"
UnboundType="GridUnboundColumnType.Decimal"
UnboundExpression="[UnitPrice] * [Quantity] * (1 - [Discount])"
DisplayFormat="c2"
Width="110px">
<FilterMenuTemplate>
<Grid_Filtering_ColumnFilterMenu_CustomRange FilterContext="context" Items="TotalPriceIntervals" />
</FilterMenuTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="Shipped"
UnboundType="GridUnboundColumnType.Boolean"
UnboundExpression="[ShippedDate] <> Null"
Width="100px" />
</Columns>
</DxGrid>
You can also handle the CustomizeFilterMenu event to customize the filter menu items for all data types. The event fires before the filter dropdown appears.
Note that each filter menu item cannot hold a complex filter condition and can only filter data by a single column value. To implement complex criteria, create a filter menu template.
The following code snippet shows how you can modify text in filter menu items. This example adds IDs to customer names.
<DxGrid Data="@customers"
FilterMenuButtonDisplayMode="GridFilterMenuButtonDisplayMode.Always"
CustomizeFilterMenu="OnCustomizeFilterMenu">
<Columns>
<DxGridDataColumn FieldName="ContactName" Width="180px" />
<DxGridDataColumn FieldName="Company" />
<DxGridDataColumn FieldName="Country" Width="140px" />
</Columns>
</DxGrid>
@code {
DateTime data { get; set; }
private Customer[]? customers;
protected override async Task OnInitializedAsync() {
customers = await CustomerData.GetData();
}
void OnCustomizeFilterMenu (GridCustomizeFilterMenuEventArgs e) {
if (e.DataColumn.FieldName == "ContactName") {
e.DataItems.ForEach(di => {
int? CustomerID = customers.Where(c =>
c.ContactName == di.Value.ToString()).FirstOrDefault()?.ID;
di.DisplayText = di.DisplayText + " (ID " + CustomerID + ")";
});
}
}
}
Custom Filter Menu Content (Template)
To apply a complex filter condition in a filter menu (for instance, a date range), create a filter menu template. You can create a template for an individual column (FilterMenuTemplate) or for all columns in the Grid (DataColumnFilterMenuTemplate).
You can choose how to display DateTime
and DateTime?
values. The default view displays dates hierarchically (HierarchicalDateView). You can also display dates as a plain list (ListView). Neither option affects the default content rendering (that is, paddings, alignment, etc.).
<DxGrid Data="GridData"
FilterMenuButtonDisplayMode="GridFilterMenuButtonDisplayMode.Always">
<Columns>
<DxGridDataColumn FieldName="OrderDate">
<FilterMenuTemplate>
@context.ListView
</FilterMenuTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="ProductName" MinWidth="100" />
<DxGridDataColumn FieldName="UnitPrice" DisplayFormat="c2" />
<DxGridDataColumn FieldName="Quantity" />
<DxGridDataColumn FieldName="Discount" DisplayFormat="p0" />
<DxGridDataColumn FieldName="Total"
UnboundType="GridUnboundColumnType.Decimal"
UnboundExpression="[UnitPrice] * [Quantity] * (1 - [Discount])"
DisplayFormat="c2" />
</Columns>
</DxGrid>
The template’s context
parameter also contains the FilterCriteria property. Use this property to specify the filter criteria applied to the column and handle the FilterCriteriaChanged event to react to filter criteria changes.
The following code snippet creates custom ranges for the Order Date and Total column’s filter menu:
<DxGrid Data="GridData"
FilterMenuButtonDisplayMode="GridFilterMenuButtonDisplayMode.Always">
<Columns>
<DxGridDataColumn FieldName="OrderDate" Width="140px">
<FilterMenuTemplate>
<DateRange FilterContext="context" />
</FilterMenuTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="ProductName" MinWidth="100" />
<DxGridDataColumn FieldName="CategoryId" Caption="Category" Width="130px">
<EditSettings>
<DxComboBoxSettings Data="Categories" ValueFieldName="CategoryId" TextFieldName="CategoryName" />
</EditSettings>
</DxGridDataColumn>
<DxGridDataColumn FieldName="UnitPrice" DisplayFormat="c2" Width="140px" />
<DxGridDataColumn FieldName="Quantity" Width="110px" />
<DxGridDataColumn FieldName="Discount" DisplayFormat="p0" Width="110px" />
<DxGridDataColumn FieldName="Total"
UnboundType="GridUnboundColumnType.Decimal"
UnboundExpression="[UnitPrice] * [Quantity] * (1 - [Discount])"
DisplayFormat="c2"
Width="110px">
<FilterMenuTemplate>
<CustomRange FilterContext="context" Items="TotalPriceIntervals" />
</FilterMenuTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="Shipped"
UnboundType="GridUnboundColumnType.Boolean"
UnboundExpression="[ShippedDate] <> Null"
Width="100px" />
</Columns>
</DxGrid>
@code {
static IReadOnlyList<CustomRangeFilterItem> TotalPriceIntervals { get; } = CreateTotalPriceIntervals();
object GridData { get; set; }
IReadOnlyList<Category> Categories { get; set; }
protected override async Task OnInitializedAsync() {
Categories = (await NwindDataService.GetCategoriesAsync()).ToList();
var invoices = await NwindDataService.GetInvoicesAsync();
var products = await NwindDataService.GetProductsAsync();
GridData = invoices.Join(products, i => i.ProductId, p => p.ProductId, (i, p) => {
return new {
ProductName = i.ProductName,
CategoryId = p.CategoryId,
OrderDate = i.OrderDate,
UnitPrice = i.UnitPrice,
Quantity = i.Quantity,
Discount = i.Discount,
ShippedDate = i.ShippedDate
};
});
}
static IReadOnlyList<CustomRangeFilterItem> CreateTotalPriceIntervals() {
var prop = new OperandProperty("Total");
var result = new List<CustomRangeFilterItem>();
var step = 100M;
for(var i = 0; i < 10; i++) {
var start = step * i;
var end = start + step;
result.Add(new() {
Criteria = prop >= start & prop < end,
DisplayText = $"from {start:c} to {end - 0.01M:c}"
});
}
result.Add(new() {
Criteria = prop > 1000,
DisplayText = $"> {1000:c}"
});
return result;
}
}
Limitations and Specifics
Take the following filter menu limitations into account:
- Filter values for date columns are rounded to dates and do not take into account time values.
- If the Grid component is bound to an instant feedback data source, the number of filter menu items is limited to 10000.
- If a hierarchical filter menu contains more than 5,000 (Blazor Server) or 1,500 (Blazor WASM) unique dates, users may notice render delays. Consider a plain list or a date range instead.
- A hierarchical filter menu treats filter items as dates and does not convert them to strings. That is why a column with a hierarchical filter menu does not support filtering by display text.
- The filter menu and filter row use the same set of filter criteria for fields and may affect each other. For example, when a user types a value in the filter row and then picks a value in a filter menu of the same column, the Grid component applies different criteria. When a user enters a value in the filter row again, the Grid applies the new operator set by the filter menu.
- A hierarchical filter menu does not support TimeOnly values.