Skip to content
IzzyBlazor 0.1.0-alpha.20

Enter all results ↑ ↓ move Esc close

FilterBuilder

Since 0.1.0-alpha.20
Builds a filter of nested groups and rules from fields.

Static server-side rendering: no circuit, no WebAssembly.

Builds a filter of nested groups and rules from fields. Apply puts it in the address (?filter=), or tells C# on an interactive page. A rule with nothing to compare is left out.

Usage

razor
<FilterBuilder Fields="DataFields.Of<Order>()" />
<FilterBuilder Fields="fields" @bind-Value="filter" />     interactive pages

Filtering a list

Use Fields to say what to build from. Apply puts the filter in the address as ?filter=, which the page reads with Filter.TryParse.

Preview

No filter: 23 of 23 orders

Code

Orders.razor
@* Apply puts the filter in the address, and the page reads it from there. *@
@using Rows = IzzyBlazor.Site.Examples.Table.Orders
@using IzzyBlazor.Site.Examples.Table
@inject NavigationManager Navigation
<Stack Gap="4" Grow>
    <FilterBuilder Fields="_fields" Name="orders-filter" />
    <TextBlock Size="TextSize.Sm" Color="Color.Muted">
        <Code>@(_filter?.ToString() ?? "No filter")</Code>: @Matches.Count of @Rows.All.Count orders
    </TextBlock>
</Stack>

@code {
    private static readonly IReadOnlyList<DataField<Order>> _fields = DataFields.Of<Order>();

    private Filter? _filter;

    private List<Order> Matches => new DataRequest<Order> { Filter = _filter }.ApplyFiltering(Rows.All.AsQueryable(), _fields).ToList();

    protected override void OnInitialized()
    {
        Navigation.LocationChanged += (_, _) => InvokeAsync(() =>
        {
            Read();
            StateHasChanged();
        });
        Read();
    }

    private void Read()
    {
        var query = new Uri(Navigation.Uri).Query;
        var text = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(query).GetValueOrDefault("orders-filter").ToString();
        _filter = Filter.TryParse(text, out var parsed) ? parsed : null;
    }
}

Details

The rows are the script's in every mode: the server draws one copy of each field's controls in a hidden block, and <ib-filter-builder> clones them. So a value's editor is a native input, a date input or a list of checkboxes, chosen by the field's type. With JavaScript off it's hidden.

Mode support

What works in each mode, FilterBuilder
FeatureStaticInteractive
Groups and rules, from a type's fields, applied with a buttonYesYes
The filter in the address, or bound to C#YesYes

Static: static server-side rendering, with no circuit and no WebAssembly. Interactive: Server, WebAssembly or Auto.

Without JavaScript

Every page starts as plain HTML: before IzzyBlazor's script loads on a static page, while an interactive page prerenders, and with JavaScript off. With JavaScript off, the builder is hidden. A filter already in the address still applies.

Accessibility

  • Each group is a fieldset whose legend names it, and every control has a name of its own.
  • Tab moves through the controls in reading order.
  • Adding a rule puts focus on its field; removing one puts it on the next rule, or the add button.
  • Each remove button says what it removes.

Parameters

FilterBuilder parameters
PropTypeDefault
FieldsThe fields to build from: DataFields.Of<Order>(), or your own.IReadOnlyList<DataField<TItem>>Required
@bind-ValueThe filter.Filter?
NameThe key in the address.string"filter"
PageKeyThe address's page number, dropped on Apply, as a new filter starts at the first page.string"page"
CursorKeyThe address's cursor, dropped on Apply as the page number is.string"cursor"
MaxDepthHow deeply groups can nest.int5
LabelIts name for screen readers.string?"Filter builder"

See also

  • FilterForm: search and filters kept in the URL.
  • DataGrid: edit, group, filter by row and arrange columns, with state in the URL.
  • Table: sort, filter, page and select, with state in the URL.

Connection lost

Rejoining the server…