blazor-docs/knowledge-base/grid-filter-date-only.md

10 KiB

title description type page_title slug position tags ticketid res_type
Filter Grid by Date Only How to filter the Grid by date values only, and ignore the time values. how-to How to Filter the Grid by Date Only grid-kb-filter-date-only grid, filter, date 1464665, 1522948, 1531072, 1559607, 1570059, 1570460 kb

Environment

Product Grid for Blazor,
TreeList for Blazor

Description

A Grid has a DateTime column with filtering. How to filter only by date and ignore the time part?

How to filter the Grid only by date without the time portion? The filter operator is equal to.

Solution

Here are 4 different ways to achieve date-only filtering with is equal to filter operator. Each option is suitable for different scenarios.

Handle OnStateChanged

This approach is suitable for [FilterMenu filter mode]({%slug grid-filter-menu%}). The Grid will reveal the filtering customization in its filter menu - the filter operators will change and the two DatePickers will show adjacent date values. After the initial is equal to filtering, the application business logic should determine how to handle the next user actions.

  1. Subscribe to the [OnStateChanged event]({%slug grid-state%}#events).
  2. Check if args.PropertyName is "FilterDescriptors".
  3. Iterate the filter descriptors in args.GridState.FilterDescriptors.
  4. If there is an active filter for the date column, [modify the filter descriptors to filter the Grid rows between two dates]({%slug grid-state%}#get-and-override-user-action-that-changes-the-grid).

Note the [difference between FilterDescriptor and CompositeFilterDescriptor]({%slug components/grid/filtering%}#filter-descriptors). This scenario involves both types.

caption Filter Grid by date via filter descriptor changes in OnStateChanged

@using Telerik.DataSource

<TelerikGrid Data="@GridData"
             TItem="@GridItem"
             Pageable="true"
             PageSize="5"
             Sortable="true"
             FilterMode="GridFilterMode.FilterMenu"
             OnStateChanged="@((GridStateEventArgs<GridItem> args) => OnStateChangedHandler(args))">
    <GridColumns>
        <GridColumn Field="@nameof(GridItem.TaskName)" Title="Task Name"></GridColumn>
        <GridColumn Field="@nameof(GridItem.TaskStart)" Title="Task Start Date" />
    </GridColumns>
</TelerikGrid>

@code {
    List<GridItem> GridData { get; set; }

    void OnStateChangedHandler(GridStateEventArgs<GridItem> args)
    {
        if (args.PropertyName == "FilterDescriptors")
        {
            foreach (CompositeFilterDescriptor cfd in args.GridState.FilterDescriptors)
            {
                FilterDescriptor fd1 = cfd.FilterDescriptors.ElementAt(0) as FilterDescriptor;
                FilterDescriptor fd2 = cfd.FilterDescriptors.ElementAt(1) as FilterDescriptor;

                if (fd1.Member == nameof(GridItem.TaskStart) &&
                    fd1.Operator == FilterOperator.IsEqualTo && // optional
                    fd1.Value != null &&
                    fd2.Value == null) // optional
                {
                    fd1.Operator = FilterOperator.IsGreaterThanOrEqualTo;
                    fd2.Operator = FilterOperator.IsLessThan;

                    fd2.Value = ((DateTime)fd1.Value).AddDays(1);
                }
            }
        }
    }

    protected override void OnInitialized()
    {
        GridData = new List<GridItem>();

        for (int i = 1; i <= 30; i++)
        {
            GridData.Add(new GridItem()
            {
                Id = i,
                TaskName = "Task Name " + i,
                TaskStart = DateTime.Now.AddDays(-i / 2).AddHours(-i).AddMinutes(-i * 5)
            });
        }

        base.OnInitialized();
    }

    public class GridItem
    {
        public int Id { get; set; }
        public string TaskName { get; set; }
        public DateTime TaskStart { get; set; }
        public DateTime TaskStartDate => TaskStart.Date;
    }
}

Bind via OnRead

This approach is suitable for [FilterRow filter mode]({%slug grid-filter-row%}). The Grid filtering interface will not reveal the filtering customization to the user.

  1. Bind the Grid via its [OnRead event]({%slug common-features-data-binding-onread%}).
  2. Check for existing filters in the [DataSourceRequest argument]({%slug common-features-data-binding-onread%}#event-argument) (args.Request.Filters).
  3. If there is an active filter for the date column, change the Operator and Value of the existing FilterDescriptor. Add one more filter descriptor for the same column (Member), so that the date column is filtered between two dates.
  4. Continue the OnRead handler execution with the modified DataSourceRequest object.

caption Filter Grid by date via filter descriptor changes in OnRead

@using Telerik.DataSource
@using Telerik.DataSource.Extensions

<TelerikGrid OnRead="@OnGridRead"
             TItem="@GridItem"
             Pageable="true"
             PageSize="5"
             Sortable="true"
             FilterMode="GridFilterMode.FilterRow">
    <GridColumns>
        <GridColumn Field="@nameof(GridItem.TaskName)" Title="Task Name"></GridColumn>
        <GridColumn Field="@nameof(GridItem.TaskStart)" Title="Task Start Date" />
    </GridColumns>
</TelerikGrid>

@code {
    List<GridItem> GridData { get; set; }

    async Task OnGridRead(GridReadEventArgs args)
    {
        await Task.Delay(200); // simulate network delay

        DateTime filterDate = DateTime.MinValue;

        foreach (CompositeFilterDescriptor cfd in args.Request.Filters)
        {
            foreach (FilterDescriptor fd in cfd.FilterDescriptors)
            {
                if (fd.Member == nameof(GridItem.TaskStart) &&
                    //fd.Operator == FilterOperator.IsEqualTo && // optional
                    fd.Value != null)
                {
                    fd.Operator = FilterOperator.IsGreaterThanOrEqualTo;
                    filterDate = (DateTime)fd.Value;
                }
            }
        }

        if (filterDate != DateTime.MinValue)
        {
            args.Request.Filters.Add(new FilterDescriptor()
            {
                Member = nameof(GridItem.TaskStart),
                MemberType = typeof(System.DateTime),
                Operator = FilterOperator.IsLessThan,
                Value = filterDate.AddDays(1)
            });
        }

        DataSourceResult result = GridData.ToDataSourceResult(args.Request);

        args.Data = result.Data;
        args.Total = result.Total;
    }

    protected override void OnInitialized()
    {
        GridData = new List<GridItem>();

        for (int i = 1; i <= 30; i++)
        {
            GridData.Add(new GridItem()
            {
                Id = i,
                TaskName = "Task Name " + i,
                TaskStart = DateTime.Now.AddDays(-i / 2).AddHours(-i).AddMinutes(-i * 5)
            });
        }

        base.OnInitialized();
    }

    public class GridItem
    {
        public int Id { get; set; }
        public string TaskName { get; set; }
        public DateTime TaskStart { get; set; }
        public DateTime TaskStartDate => TaskStart.Date;
    }
}

Use Additional Model Property

This approach is suitable for both filter menu and filter row modes. It has the following specifics:

  • Sorting will ignore the time values, unless there is an extra column, which is bound to the complete DateTime value.
  • Time value display requires a [column Template]({%slug grid-templates-column%}) or an extra "time" column.
  • Time value editing requires an [EditorTemplate]({%slug grid-templates-editor%}).

caption Filter Grid by date via additional model property

<TelerikGrid Data="@GridData"
             TItem="@GridItem"
             Pageable="true"
             PageSize="5"
             Sortable="true"
             FilterMode="GridFilterMode.FilterRow"
             EditMode="@GridEditMode.Incell"
             OnUpdate="@OnGridUpdate">
    <GridColumns>
        <GridColumn Field="@nameof(GridItem.TaskName)" Title="Task Name"></GridColumn>
        <GridColumn Field="@nameof(GridItem.TaskStartDate)" Title="Task Start Date">
            <Template>
                @((context as GridItem).TaskStart.ToString())
            </Template>
            <EditorTemplate>
                @{
                    var item = context as GridItem;
                }
                <TelerikDateTimePicker @bind-Value="@item.TaskStart"
                                       DebounceDelay="0" />
            </EditorTemplate>
        </GridColumn>
    </GridColumns>
</TelerikGrid>

@code {
    List<GridItem> GridData { get; set; }

    void OnGridUpdate(GridCommandEventArgs args)
    {
        var item = args.Item as GridItem;
        var index = GridData.FindIndex(x => x.Id == item.Id);
        GridData[index] = item;
    }

    protected override void OnInitialized()
    {
        GridData = new List<GridItem>();

        for (int i = 1; i <= 30; i++)
        {
            GridData.Add(new GridItem()
            {
                Id = i,
                TaskName = "Task Name " + i,
                TaskStart = DateTime.Now.AddDays(-i / 2).AddHours(-i).AddMinutes(-i * 5)
            });
        }

        base.OnInitialized();
    }

    public class GridItem
    {
        public int Id { get; set; }
        public string TaskName { get; set; }
        public DateTime TaskStart { get; set; }
        public DateTime TaskStartDate => TaskStart.Date;
    }
}

Use Filter Template

  • This approach is suitable for [FilterMenu filter mode]({%slug grid-filter-menu%}).
  • The date column requires a [FilterMenuTemplate]({%slug grid-templates-filter%}).
  • The filter menu template provides full control over filtering interface and behavior.
  • More coding may be required.

See the Grid Filter Menu Template Demo.

See Also

  • [Grid State]({%slug grid-state%})
  • [Grid Filtering Overview]({%slug components/grid/filtering%})
  • [Grid Manual Data Operations with OnRead]({%slug components/grid/manual-operations%})