Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 51 additions & 26 deletions src/MudBlazor.Docs/Pages/Components/DataGrid/DataGridPage.razor
Comment thread
versile2 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -218,36 +218,61 @@
<DocsPageSection>
<SectionHeader Title="Filtering">
<Description>
The <CodeInline>&lt;MudDataGrid></CodeInline> supports filtering with several different <CodeInline>DataGridFilterMode</CodeInline>s by setting the <CodeInline>FilterMode</CodeInline> property.
<CodeInline>DataGridFilterMode.Simple</CodeInline> is the default where all filters are managed in one popover in the data grid. It allows you to
set multiple filters at one time for multiple different columns. In <CodeInline>DataGridFilterMode.ColumnFilterMenu</CodeInline> mode, there is a dedicated popover for
each column. Lastly, <CodeInline>DataGridFilterMode.ColumnFilterRow</CodeInline> allows you to inline the filtering behavior directly into the data grid.
<CodeInline>&lt;MudDataGrid></CodeInline> supports filtering with several <CodeInline>DataGridFilterMode</CodeInline> settings through the <CodeInline>FilterMode</CodeInline> parameter.
<br>
• <CodeInline>Simple</CodeInline> is the <b>default</b>. All filters are managed in a single popover, and you can set multiple filters across multiple columns.
<br>
• <CodeInline>ColumnFilterMenu</CodeInline> provides a dedicated popover for each column.
<br>
• <CodeInline>ColumnFilterRow</CodeInline> places the filtering UI inline in the grid.
<br><br>
Is it possible to define the case sensitivity when filtering string values by setting the parameter <CodeInline>FilterCaseSensitivity</CodeInline>.
</Description>
</SectionHeader>
<SectionContent DarkenBackground="true" Code="@nameof(DataGridFilteringExample)" ShowCode="false" Block="true" FullWidth="true">
<DataGridFilteringExample />
</SectionContent>
</DocsPageSection>

<DocsPageSection>
<SectionHeader Title="Advanced Filtering">
<Description>
It is possible to customize filtering by utilizing the <CodeInline>&lt;FilterTemplate></CodeInline> available on the <CodeInline>&lt;MudDataGrid></CodeInline>
as well as each <CodeInline>&lt;Column></CodeInline>. In the example below, the Sign column is customized.
<br><br>
Inside the <CodeInline>&lt;FilterTemplate></CodeInline> on the data grid while using <CodeInline>DataGridFilterMode.Simple</CodeInline>, the context is set to the
data grid's FilterDefinitions to allow for customizing the filtering behavior.
String filtering case sensitivity can be configured globally with <CodeInline>FilterCaseSensitivity</CodeInline>.
<br><br>
When using the <CodeInline>&lt;FilterTemplate></CodeInline> in the column specific filter modes, the context is a <CodeInline>DataGridFilterMode.Simple</CodeInline>
which gives access to several helpful properties and actions. For example, the current <CodeInline>FilterDefinition</CodeInline> related to the column is available as well
as several actions to make it easier to implement custom filter behavior such as <CodeInline>ApplyFilter</CodeInline> and <CodeInline>ClearFilter</CodeInline>.
For backend data scenarios, see <MudLink Href="/components/datagrid#server-side-filtering-sorting-and-pagination">Server Side Filtering, Sorting and Pagination</MudLink>.
<br /><br/>
QuickFilter is shown in <MudLink Href="/components/datagrid#advanced-data-grid">Advanced Data Grid</MudLink>.
</Description>
</SectionHeader>
<SectionContent DarkenBackground="true" Code="@nameof(DataGridAdvancedFilteringExample)" ShowCode="false" Block="true" FullWidth="true">
<DataGridAdvancedFilteringExample />
</SectionContent>

<DocsPageSection>
<SectionHeader Title="Basic">
<Description>
This example demonstrates the built-in filtering UI using the same items and paging setup. Use it to compare each <CodeInline>DataGridFilterMode</CodeInline> option and see how <CodeInline>FilterCaseSensitivity</CodeInline> affects string filtering.
</Description>
</SectionHeader>
<SectionContent DarkenBackground="true" Code="@nameof(DataGridFilteringExample)" ShowCode="false" Block="true" FullWidth="true">
<DataGridFilteringExample />
</SectionContent>
</DocsPageSection>

<DocsPageSection>
<SectionHeader Title="Simple FilterTemplate">
<Description>
In <CodeInline>DataGridFilterMode.Simple</CodeInline>, you can keep the built-in simple filter panel and customize a column with <CodeInline>&lt;Column&gt;.&lt;FilterTemplate&gt;</CodeInline>, or replace the panel with <CodeInline>&lt;MudDataGrid&gt;.&lt;FilterTemplate&gt;</CodeInline>. This example uses a toggle to switch between those two approaches.
<br /><br />
<CodeInline>&lt;MudDataGrid&gt;.&lt;FilterTemplate&gt;</CodeInline> receives <CodeInline>MudDataGrid&lt;T&gt;</CodeInline>, while <CodeInline>&lt;Column&gt;.&lt;FilterTemplate&gt;</CodeInline> receives <CodeInline>FilterContext&lt;T&gt;</CodeInline>. <CodeInline>FilterContext&lt;T&gt;</CodeInline> provides the active filter definition and actions to apply, clear, or close the current filter UI. These actions operate on the filter UI surface that owns the template.
<br /><br />
The Category column template maps selected values to the active filter definition and applies a custom <CodeInline>FilterFunction</CodeInline> for multi-select matching. The grid template replaces the built-in panel and syncs the custom Name and Category inputs to the grid filters. For exact member details, see the API section.
</Description>
</SectionHeader>
<SectionContent DarkenBackground="true" Code="@nameof(DataGridFilterTemplateSimpleModeExample)" ShowCode="false" Block="true" FullWidth="true">
<DataGridFilterTemplateSimpleModeExample />
</SectionContent>
</DocsPageSection>

<DocsPageSection>
<SectionHeader Title="Row and Menu FilterTemplate">
<Description>
<CodeInline>&lt;Column&gt;.&lt;FilterTemplate&gt;</CodeInline> also works in <CodeInline>DataGridFilterMode.ColumnFilterRow</CodeInline> and <CodeInline>DataGridFilterMode.ColumnFilterMenu</CodeInline>. These modes also use <CodeInline>FilterContext&lt;T&gt;</CodeInline>, so the same context shape is reused while <CodeInline>Actions</CodeInline> operate on the currently rendered filter UI.
<br /><br />
This example keeps the built-in filter behavior for most columns and overrides one column with a custom multi-select filter. In <CodeInline>DataGridFilterMode.ColumnFilterMenu</CodeInline>, the filter is applied manually through the grid so the menu can stay open while selections change. For exact member details, see the <MudLink Href="/api/muddatagrid">API</MudLink> section.
</Description>
</SectionHeader>
<SectionContent DarkenBackground="true" Code="@nameof(DataGridAdvancedFilteringExample)" ShowCode="false" Block="true" FullWidth="true">
<DataGridAdvancedFilteringExample />
</SectionContent>
</DocsPageSection>

</DocsPageSection>

<DocsPageSection>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,111 +1,109 @@
@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@using MudBlazor.Examples.Data.Models
@namespace MudBlazor.Docs.Examples
@inject HttpClient httpClient

<MudDataGrid T="Element" Items="@Elements" Filterable="true" FilterMode="@DataGridFilterMode.ColumnFilterRow">
<MudDataGrid @ref="@_dataGrid" Items="@_elements" Filterable="true" FilterMode="@_filterMode" RowsPerPage="5">
<Columns>
<PropertyColumn Property="x => x.Number" Title="Nr" Filterable="false" />
<PropertyColumn Property="x => x.Sign">
<PropertyColumn Property="x => x.Sign" />
<PropertyColumn Property="x => x.Name" />
<PropertyColumn Property="x => x.Position" Filterable="false" />
<PropertyColumn Property="x => x.Molar" Title="Molar mass" />
<PropertyColumn Property="x => x.Group" Title="Category">
<FilterTemplate>
<MudIconButton OnClick="@OpenFilter" Icon="@_icon" Size="@Size.Small" />
<MudOverlay Visible="@_filterOpen" OnClick="@(() => _filterOpen = false)" />
<MudPopover Open="@_filterOpen" AnchorOrigin="Origin.BottomCenter" TransformOrigin="Origin.TopCenter"
Style="width:150px">
<MudStack Spacing="0">
<MudCheckBox T="bool" Label="Select All" Size="@Size.Small" Value="@_selectAll" ValueChanged="@SelectAll" />
<MudStack Spacing="0" Style="overflow-y:auto;max-height:250px">
@foreach (var item in context.Items)
{
<MudCheckBox T="bool" Label="@($"{item.Sign}")" Size="@Size.Small" Value="@(_selectedItems.Contains(item))"
ValueChanged="@((value) => SelectedChanged(value, item))" />
}
</MudStack>
<MudStack Row="true">
<MudButton OnClick="@(() => ClearFilterAsync(context))">Clear</MudButton>
<MudButton Color="@Color.Primary" OnClick="@(() => ApplyFilterAsync(context))">Filter</MudButton>
</MudStack>
</MudStack>
</MudPopover>
<MudSelect T="string" MultiSelection="true"
SelectedValues="@GetFilterValues(context.FilterDefinition!)"
SelectedValuesChanged="@(values => SetColumnFilterValues(context, values))"
FullWidth="true" Dense="true" Margin="@Margin.Dense"
Class="filter-input category-filter"
Placeholder="Filter Categories" Clearable="true">
@foreach (var category in _categories)
{
<MudSelectItem T="string" Value="@category">@category</MudSelectItem>
}
</MudSelect>
</FilterTemplate>
</PropertyColumn>
<PropertyColumn Property="x => x.Name" />
<PropertyColumn Property="x => x.Position" />
<PropertyColumn Property="x => x.Molar" Title="Molar mass" />
<PropertyColumn Property="x => x.Group" Title="Category" />
</Columns>
<PagerContent>
<MudDataGridPager T="Element" />
<MudDataGridPager T="Element" PageSizeOptions="new[] { 5 }" />
</PagerContent>
</MudDataGrid>

@code {
IEnumerable<Element> Elements = new List<Element>();
HashSet<Element> _selectedItems = new();
HashSet<Element> _filterItems = new();
FilterDefinition<Element> _filterDefinition;
bool _selectAll = true;
string _icon = Icons.Material.Outlined.FilterAlt;
<div class="d-flex justify-start mt-4">
<MudRadioGroup T="DataGridFilterMode" Value="@_filterMode" ValueChanged="@FilterModeChanged">
<MudRadio Dense="true" Value="@DataGridFilterMode.ColumnFilterRow" Color="Color.Primary">Column Filter Row</MudRadio>
<MudRadio Dense="true" Value="@DataGridFilterMode.ColumnFilterMenu" Color="Color.Tertiary">Column Filter Menu</MudRadio>
</MudRadioGroup>
</div>

bool _filterOpen = false;
@code {
private readonly List<Element> _elements = CreateElements();
private readonly List<string> _categories = [];
private MudDataGrid<Element> _dataGrid = default!;
private DataGridFilterMode _filterMode = DataGridFilterMode.ColumnFilterRow;

protected override async Task OnInitializedAsync()
protected override void OnInitialized()
{
Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
_selectedItems = Elements.ToHashSet();
_filterItems = Elements.ToHashSet();
_filterDefinition = new FilterDefinition<Element>
{
FilterFunction = x => _filterItems.Contains(x)
};
_categories.AddRange(_elements.Select(x => x.Group).Distinct().OrderBy(x => x).ToList());
}

void OpenFilter()
private Task FilterModeChanged(DataGridFilterMode value)
{
_filterOpen = true;
// Example toggle: switches between the row and menu column filter modes.
_filterMode = value;
return _dataGrid.ClearFiltersAsync();
}

private void SelectedChanged(bool value, Element item)
private IReadOnlyCollection<string> GetFilterValues(IFilterDefinition<Element> filterDefinition)
{
if (value)
_selectedItems.Add(item);
else
_selectedItems.Remove(item);

if (_selectedItems.Count == Elements.Count())
_selectAll = true;
else
_selectAll = false;
// Column FilterTemplate: reads the current values from the active filter UI.
return filterDefinition.Value as IReadOnlyCollection<string> ?? Array.Empty<string>();
}

private async Task ClearFilterAsync(FilterContext<Element> context)
private Task SetColumnFilterValues(FilterContext<Element> context, IEnumerable<string> values)
{
_selectedItems = Elements.ToHashSet();
_filterItems = Elements.ToHashSet();
_icon = Icons.Material.Outlined.FilterAlt;
await context.Actions.ClearFilterAsync(_filterDefinition);
_filterOpen = false;
}
// Column FilterTemplate: maps selected values to the active filter definition and applies through the grid so the menu can stay open for multi-selection.
var filterDefinition = context.FilterDefinition!;
var selectedValues = values?.ToList() ?? [];
filterDefinition.Value = selectedValues.Count > 0 ? selectedValues : null;

private async Task ApplyFilterAsync(FilterContext<Element> context)
{
_filterItems = _selectedItems.ToHashSet();
_icon = _filterItems.Count == Elements.Count() ? Icons.Material.Outlined.FilterAlt : Icons.Material.Filled.FilterAlt;
await context.Actions.ApplyFilterAsync(_filterDefinition);
_filterOpen = false;
if (filterDefinition is FilterDefinition<Element> filterDef)
{
if (selectedValues.Count > 0)
{
filterDef.FilterFunction = item => item.Group is not null && selectedValues.Contains(item.Group);
}
else
{
filterDef.FilterFunction = null;
}
}

return ApplyColumnFilterWithoutClosingAsync(context, filterDefinition);
}

private void SelectAll(bool value)
private Task ApplyColumnFilterWithoutClosingAsync(FilterContext<Element> context, IFilterDefinition<Element> filterDefinition)
{
_selectAll = value;

if (value)
// Column FilterTemplate: refreshes filtering through the grid instead of the menu action so the menu stays open while selections change.
if (context.FilterDefinitions.All(x => x.Id != filterDefinition.Id))
{
_selectedItems = Elements.ToHashSet();
}
else
{
_selectedItems.Clear();
context.FilterDefinitions.Add(filterDefinition);
}

return _dataGrid.AddFilterAsync(filterDefinition);
}

private static List<Element> CreateElements() =>
[
new() { Number = 1, Sign = "H", Name = "Hydrogen", Position = 1, Molar = 1.008, Group = "Nonmetal" },
new() { Number = 2, Sign = "He", Name = "Helium", Position = 18, Molar = 4.0026, Group = "Noble Gas" },
new() { Number = 3, Sign = "Li", Name = "Lithium", Position = 1, Molar = 6.94, Group = "Alkali Metal" },
new() { Number = 4, Sign = "Be", Name = "Beryllium", Position = 2, Molar = 9.0122, Group = "Alkaline Earth Metal" },
new() { Number = 5, Sign = "B", Name = "Boron", Position = 13, Molar = 10.81, Group = "Metalloid" },
new() { Number = 6, Sign = "C", Name = "Carbon", Position = 14, Molar = 12.011, Group = "Nonmetal" },
new() { Number = 7, Sign = "N", Name = "Nitrogen", Position = 15, Molar = 14.007, Group = "Nonmetal" },
new() { Number = 8, Sign = "O", Name = "Oxygen", Position = 16, Molar = 15.999, Group = "Nonmetal" },
new() { Number = 9, Sign = "F", Name = "Fluorine", Position = 17, Molar = 18.998, Group = "Halogen" },
new() { Number = 10, Sign = "Ne", Name = "Neon", Position = 18, Molar = 20.180, Group = "Noble Gas" }
];
}
Loading
Loading