DataFilter - filter is not empty or is required?

Hi,
I am using a data filter here is my sample code. I wonder if I can use the required validator in order to make the user select dates or pop up an alert when pressing the apply filter button.
I want the data to come to the data grid when the button is pressed (after the button press data is loaded to the grid), not when the page is loaded. So is it possible to bind button action to a method by getting the data filter selection?

Thank you.

<RadzenCard class="mb-3">
    <RadzenDataFilter @ref="_dataFilter" Auto=_auto Data="@_reconciliations" TItem="RazerReconciliations" ViewChanged=@(view => _filteredOrders = view.ToList())
                      FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive">
        <Properties>
            <MyCustomDataFilterProperty TItem="RazerReconciliations" Property="TransactionDateTime" Title="Transaction Start Date" FormatString="{0:d}"/>
            <MyCustomDataFilterProperty TItem="RazerReconciliations" Property="TransactionDateTime" Title="Transaction End Date" FormatString="{0:d}" />
            
        </Properties>
    </RadzenDataFilter>
    <RadzenButton Text="Apply Filter" Click="@(args => _dataFilter.Filter())" id="btn"/>
</RadzenCard>

You can define a DatePicker and desired validator in a TemplateForm using FilterTemplate:


and perform the validation on filter button click:

1 Like

Thank you @enchev for your help. One last thing about the data filter, how to filter for a date range? I mean I want to apply the filter for TransactionDateTime but somehow both filters get the same date when I change them. What I am doing wrong? Can you please help?

<RadzenCard class="mb-3">
    <RadzenDataFilter @ref="_dataFilter" Auto=_auto Data="@_reconciliations" TItem="RazerReconciliations" ViewChanged=@(view => _filteredOrders = view.ToList())
                      FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive">
        <Properties>
            <MyCustomDataFilterProperty TItem="RazerReconciliations" Property="TransactionDateTime" Title="Transaction Date" FilterValue="@selectedStartDate">
                <FilterTemplate Context="filterContext">
                    <RadzenTemplateForm TItem="object" @ref="formStart" Data="@("dummyStart")">
                        <RadzenDatePicker @bind-Value=selectedStartDate Name="TransactionDateTime" DateFormat="d" />
                        <RadzenRequiredValidator Component="TransactionDateTime" />
                    </RadzenTemplateForm>
                </FilterTemplate>
            </MyCustomDataFilterProperty>
            <MyCustomDataFilterProperty TItem="RazerReconciliations" Property="TransactionDateTime" Title="Transaction Date" FilterValue="@selectedEndDate">
                <FilterTemplate Context="filterContext">
                    <RadzenTemplateForm TItem="object" @ref="formEnd" Data="@("dummyEnd")">
                        <RadzenDatePicker @bind-Value=selectedEndDate Name="TransactionDateTime" DateFormat="d" />
                        <RadzenRequiredValidator Component="TransactionDateTime" />
                    </RadzenTemplateForm>
                </FilterTemplate>
            </MyCustomDataFilterProperty>
        </Properties>
    </RadzenDataFilter>
    <RadzenButton Text="Apply Filter" Click=@Filter id="btn" />
</RadzenCard>

Do you have a solution suggestion for this issue @enchev ? Is there a FilterOperator like between?

I'm afraid that I don't have any suggestion. Two filters with using >= and =< is best I can think of.

I did try to use two filters for Transaction Date as you said but somehow the date gets the same value. You can see this in my previous post.

The problem is caused by the fact that you've declared two RadzenDataFilterProperty with same Property value (Property="TransactionDateTime").

You can have two filters for a single property:

Can I somehow get the dates selected in order to use them in my query to populate data in the grid when the user clicks apply filter button?

<RadzenDataFilter @ref="_dataFilter" Auto=_auto Data="@_reconciliations" TItem="RazerReconciliations" ViewChanged=@(view => _filteredOrders = view.ToList())
                      FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive">
        <Properties>
            <MyCustomDataFilterProperty TItem="RazerReconciliations" Property="TransactionDateTime" Title="Transaction Date" FormatString="{0:d}">
                
            </MyCustomDataFilterProperty>
           
        </Properties>
    </RadzenDataFilter>
<RadzenButton Text="Apply Filter" Click=@Filter id="btn" />

Apply Filter click:

async Task Filter()
    {
        if (formStart.EditContext.Validate())
        {
            
            await _dataFilter.Filter();
            await ShowLoading();
            _reconciliationResults = await ViewReconciliationsUseCase.ExecuteAsync(**selectedStartDate**, **selectedEndDate**);
        }
    }

I see what you are after however we need to introduce breaking change in order to support such scenario and we are willing to do that. We need to change the Context of the FilterTemplate to the actual underlying filter:

Once you have access to the underlying filter you can bind the FilterValue to desired component:

You can also remove the TemplateForm and use much simple validation:



You can also access all filters from the DataFilter instance:


The change is already in our master branch and it will be released with our next update early next week:

Here is also the entire code:

@page "/datafilter"

@using RadzenBlazorDemos.Data
@using RadzenBlazorDemos.Models.Northwind
@using Microsoft.EntityFrameworkCore

@inherits DbContextPage

<RadzenExample Name="DataFilter" AdditionalSourceCodePages=@(new List<string>() { "MyCustomDataFilterProperty.razor" }) Documentation="false">
<div class="container-fluid">
    <div class="row">
        <div class="col">
            <RadzenCard class="mb-3" style="display: flex; align-items: center; gap: 0.5rem">
                <RadzenCheckBox @bind-Value="@auto" Name="auto" />
                <RadzenLabel Text="Auto filter" Component="auto" Style="margin-left: 8px; margin-right: 32px; vertical-align: middle;" />
                <RadzenButton Text="Apply Filter" Click="@Filter" Disabled="@auto" />
            </RadzenCard>
            <RadzenCard class="mb-3">
                <RadzenDataFilter @ref="dataFilter" Auto=auto Data="@orders" TItem="Order" ViewChanged=@(view => filteredOrders = view.ToList())>
                    <Properties>
                        <RadzenDataFilterProperty TItem="Order" Property="OrderID" Title="Order ID" FilterValue="@selectedIds" 
                            Type="typeof(IEnumerable<int>)" FilterOperator="FilterOperator.Contains">
                            <FilterTemplate Context="filterContext">
                                    <RadzenDropDown @bind-Value=@selectedIds Style="width:100%;"
                                    Change=@OnSelectedIdsChange Data="@(orderIds)" AllowClear="true" Multiple="true" />
                            </FilterTemplate>
                        </RadzenDataFilterProperty>
                        <RadzenDataFilterProperty TItem="Order" Property="Employee.LastName" Title="Employee Last Name" />
                        <MyCustomDataFilterProperty TItem="Order" Property="OrderDate" Title="Order Date">
                            <FilterTemplate Context="filterContext">
                                <RadzenDatePicker @bind-Value=@(filterContext.FilterValue) Name="OrderDate" AllowClear />
                                <RadzenLabel Component="OrderDate" Text="Required" Style="color: red;" Visible=@(filterContext.FilterValue == null) />
                            </FilterTemplate>
                        </MyCustomDataFilterProperty>
                        <RadzenDataFilterProperty TItem="Order" Property="Freight" Title="Freight" />
                    </Properties>
                </RadzenDataFilter>
            </RadzenCard>
            <RadzenDataGrid @ref="ordersGrid" AllowPaging="true" AllowSorting="true" Data="@(filteredOrders ?? orders)" TItem="Order"
                ColumnWidth="200px" PageSize="20" Style="height: 500px">
                <Columns>
                    <RadzenDataGridColumn Width="50px" TItem="Order" Title="#" Filterable="false" Sortable="false" TextAlign="TextAlign.Center" Frozen=true>
                        <Template>
                            @(orders.IndexOf(context) + 1)
                        </Template>
                    </RadzenDataGridColumn>
                    <RadzenDataGridColumn Width="200px" TItem="Order" Property="OrderID" Title="Order ID">
                        <FooterTemplate>
                            Displayed orders: <b>@ordersGrid.View.Count()</b> of <b>@orders.Count()</b>
                        </FooterTemplate>
                    </RadzenDataGridColumn>
                    <RadzenDataGridColumn Width="200px" TItem="Order" Property="Customer.CompanyName" Title="Customer" />
                    <RadzenDataGridColumn TItem="Order" Property="Employee.LastName" Title="Employee">
                        <Template Context="order">
                            @order.Employee?.FirstName @order.Employee?.LastName
                        </Template>
                    </RadzenDataGridColumn>
                    <RadzenDataGridColumn TItem="Order" Property="OrderDate" Title="Order Date" FormatString="{0:d}">
                        <FooterTemplate>
                            Last order date: <b>@String.Format("{0:d}", orders.OrderByDescending(o => o.OrderDate).LastOrDefault()?.OrderDate)</b>
                        </FooterTemplate>
                    </RadzenDataGridColumn>
                    <RadzenDataGridColumn TItem="Order" Property="Freight" Title="Freight">
                        <Template Context="order">
                            @String.Format(new System.Globalization.CultureInfo("en-US"), "{0:C}", order.Freight)
                        </Template>
                        <FooterTemplate>
                            Total amount: <b>@String.Format(new System.Globalization.CultureInfo("en-US"), "{0:C}", orders.Sum(o => o.Freight))</b>
                        </FooterTemplate>
                    </RadzenDataGridColumn>
                    <RadzenDataGridColumn TItem="Order" Property="ShipName" Title="Ship Name" />
                </Columns>
            </RadzenDataGrid>
        </div>
    </div>
</div>
</RadzenExample>

@code {
    RadzenTemplateForm<object> form;

    async Task Filter()
    {
        if (!dataFilter.Filters.Any(f => f.FilterValue == null))
        {
            await dataFilter.Filter();
        }
    }

    bool auto = true;
    RadzenDataFilter<Order> dataFilter;

    IList<Order> filteredOrders;
    IList<Order> orders;
    RadzenDataGrid<Order> ordersGrid;

    IEnumerable<int> selectedIds;
    IEnumerable<int> orderIds;

    void OnSelectedIdsChange(object value)
    {
        if (selectedIds != null && !selectedIds.Any())
        {
            selectedIds = null;
        }
    }

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();

        orders = dbContext.Orders.Include("Customer").Include("Employee").ToList();
        orderIds = orders.Select(o => o.OrderID).Distinct();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (firstRender)
        {
            await dataFilter.AddFilter(new CompositeFilterDescriptor() 
            { 
                Property = "OrderDate", 
                FilterValue = DateTime.Now, 
                FilterOperator = FilterOperator.GreaterThanOrEquals 
            });

            await dataFilter.AddFilter(new CompositeFilterDescriptor() 
            { 
                Property = "OrderDate", 
                FilterValue = DateTime.Now.AddDays(10), 
                FilterOperator = FilterOperator.LessThanOrEquals 
            });
        }
    }
}

Thank you, I will looking forward to it :slight_smile: