Filter Grid by Date Only
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.
- Use the Grid
OnStateChanged
event - Bind the Grid via
OnRead
event - Use an additional model property
- Use a filter template
Handle OnStateChanged
This approach is suitable for FilterMenu
filter mode. 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.
- Subscribe to the
OnStateChanged
event. - Check if
args.PropertyName
is"FilterDescriptors"
. - Iterate the filter descriptors in
args.GridState.FilterDescriptors
. - If there is an active filter for the date column, modify the filter descriptors to filter the Grid rows between two dates.
Note the difference between FilterDescriptor
and CompositeFilterDescriptor
. This scenario involves both types.
@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. The Grid filtering interface will not reveal the filtering customization to the user.
- Bind the Grid via its
OnRead
event. - Check for existing filters in the
DataSourceRequest
argument (args.Request.Filters
). - If there is an active filter for the date column, change the
Operator
andValue
of the existingFilterDescriptor
. Add one more filter descriptor for the same column (Member
), so that the date column is filtered between two dates. - Continue the
OnRead
handler execution with the modifiedDataSourceRequest
object.
@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
or an extra "time" column. - Time value editing requires an
EditorTemplate
.
<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. - The date column requires a
FilterMenuTemplate
. - The filter menu template provides full control over filtering interface and behavior.
- More coding may be required.
See the Grid Filter Menu Template Demo.