Skip to content

Commit 427bab3

Browse files
kendo-botKB Botxristianstefanov
authored
Added new kb article grid-dynamically-updating-filtermenutemplate-value (#2800)
* Added new kb article grid-dynamically-updating-filtermenutemplate-value * chore(Grid): add suggestions as per comments --------- Co-authored-by: KB Bot <[email protected]> Co-authored-by: Hristian Stefanov <[email protected]>
1 parent a3625f4 commit 427bab3

File tree

1 file changed

+206
-0
lines changed

1 file changed

+206
-0
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
---
2+
title: FilterMenuTemplate Not Updating After Dynamic Value Change
3+
description: Learn how to refresh and update the displayed value within a FilterMenuTemplate when its value changes dynamically in Grid for Blazor.
4+
type: troubleshooting
5+
page_title: Refreshing FilterMenuTemplate to Reflect Dynamic Value Changes in Blazor Grid
6+
slug: grid-kb-dynamically-updating-filtermenutemplate-value
7+
tags: grid, blazor, filter, filtermenutemplate
8+
res_type: kb
9+
ticketid: 1677674
10+
---
11+
12+
## Environment
13+
14+
<table>
15+
<tbody>
16+
<tr>
17+
<td>Product</td>
18+
<td>Grid for Blazor</td>
19+
</tr>
20+
</tbody>
21+
</table>
22+
23+
## Description
24+
25+
I have a custom `FilterMenuTemplate` for a column where a slider is shown. Although filtering works as expected, the `<span>` within the `FilterMenuTemplate` that is supposed to show the current selected value does not update when the slider value changes.
26+
27+
## Cause
28+
29+
The [`FilterMenuTemplate`](slug:grid-templates-filter#filter-menu-template) does not refresh automatically when the value bound to a control within it, such as a slider, changes dynamically.
30+
31+
## Solution
32+
33+
To resolve this issue, encapsulate the content of the `FilterMenuTemplate` in a separate Razor component. Then, refresh this component upon any value change in the Slider. This approach ensures that the displayed value updates dynamically to reflect the current selection. Follow the steps below to implement this solution:
34+
35+
1. Create a separate Razor component (for example, `CustomFilterMenu.razor`) that will contain the `FilterMenuTemplate` content, including the slider and the span displaying the selected value.
36+
37+
2. In your `CustomFilterMenu.razor`, define the necessary parameters and logic to handle the value change and update the display.
38+
39+
3. Use this component within the `FilterMenuTemplate` of the desired column in your Grid.
40+
41+
4. Ensure that any value change in the slider triggers the component's refresh to update the displayed value accordingly.
42+
43+
`````RAZOR
44+
@using Telerik.DataSource
45+
46+
<TelerikGrid Data="@GridData"
47+
FilterMode="@GridFilterMode.FilterMenu"
48+
Pageable="true"
49+
Width="600px">
50+
<GridColumns>
51+
<GridColumn Field="@(nameof(Product.Name))" Title="Product" Filterable="false" />
52+
<GridColumn Field="@(nameof(Product.Price))">
53+
<FilterMenuTemplate>
54+
<CustomPriceFilter @bind-SelectedPrice="@SelectedPrice"
55+
Context="context" />
56+
</FilterMenuTemplate>
57+
</GridColumn>
58+
59+
<GridColumn Field="@(nameof(Product.Size))">
60+
<FilterMenuTemplate>
61+
@foreach (var size in Sizes)
62+
{
63+
<div>
64+
<TelerikCheckBox Value="@(IsCheckboxInCurrentFilter(context.FilterDescriptor, size))"
65+
TValue="bool"
66+
ValueChanged="@((value) => UpdateCheckedSizes(value, size, context))"
67+
Id="@($"size_{size}")">
68+
</TelerikCheckBox>
69+
<label for="@($"size_{size}")">
70+
@if (size == null) // part of handling nulls - show meaningful text for the end user
71+
{
72+
<text>Empty</text>
73+
}
74+
else
75+
{
76+
@size
77+
}
78+
</label>
79+
</div>
80+
}
81+
</FilterMenuTemplate>
82+
</GridColumn>
83+
</GridColumns>
84+
</TelerikGrid>
85+
86+
@code {
87+
private List<Product> GridData { get; set; }
88+
89+
private string[] Sizes = new string[] { "XS", "S", "M", "L", "XL", null };
90+
91+
private double SelectedPrice { get; set; }
92+
93+
private void OnPriceChanged(double value, FilterMenuTemplateContext context)
94+
{
95+
SelectedPrice = value;
96+
context.FilterDescriptor.FilterDescriptors.Clear();
97+
context.FilterDescriptor.FilterDescriptors.Add(new FilterDescriptor(nameof(Product.Price), FilterOperator.IsGreaterThanOrEqualTo, value));
98+
}
99+
100+
private bool IsCheckboxInCurrentFilter(CompositeFilterDescriptor filterDescriptor, string size)
101+
{
102+
if (size == null)
103+
{
104+
foreach (FilterDescriptor item in filterDescriptor.FilterDescriptors)
105+
{
106+
if (item.Operator == FilterOperator.IsNull)
107+
{
108+
return true;
109+
}
110+
}
111+
return false;
112+
}
113+
return filterDescriptor.FilterDescriptors.Select(f => (f as FilterDescriptor).Value?.ToString()).ToList().Contains(size);
114+
}
115+
116+
private void UpdateCheckedSizes(bool isChecked, string itemValue, FilterMenuTemplateContext context)
117+
{
118+
var compositeFilterDescriptor = context.FilterDescriptor;
119+
compositeFilterDescriptor.LogicalOperator = FilterCompositionLogicalOperator.Or;
120+
121+
if (!isChecked)
122+
{
123+
compositeFilterDescriptor.FilterDescriptors.Remove(compositeFilterDescriptor.FilterDescriptors.First(x =>
124+
{
125+
var fd = x as FilterDescriptor;
126+
if ((fd.Operator == FilterOperator.IsNull && itemValue == null) ||
127+
(fd.Operator == FilterOperator.IsEqualTo && fd.Value?.ToString() == itemValue))
128+
{
129+
return true;
130+
}
131+
else
132+
{
133+
return false;
134+
}
135+
}));
136+
}
137+
else
138+
{
139+
compositeFilterDescriptor.FilterDescriptors.Add(new FilterDescriptor()
140+
{
141+
Member = nameof(Product.Size),
142+
MemberType = typeof(string),
143+
Operator = itemValue == null ? FilterOperator.IsNull : FilterOperator.IsEqualTo,
144+
Value = itemValue
145+
});
146+
}
147+
}
148+
149+
protected override void OnInitialized()
150+
{
151+
GridData = Enumerable.Range(1, 70).Select(x => new Product
152+
{
153+
Id = x,
154+
Size = Sizes[x % Sizes.Length],
155+
Name = $"Product {x}",
156+
Price = x
157+
}).ToList();
158+
159+
base.OnInitialized();
160+
}
161+
}
162+
`````
163+
`````RAZOR CustomPriceFilter.razor
164+
@using Telerik.DataSource
165+
166+
<TelerikStackLayout HorizontalAlign="@StackLayoutHorizontalAlign.Center" Orientation="StackLayoutOrientation.Vertical">
167+
<span>@SelectedPrice</span>
168+
<TelerikSlider ShowButtons="false"
169+
TickPosition="SliderTickPosition.None"
170+
Min="0"
171+
Max="100"
172+
Width="100%"
173+
LargeStep="10"
174+
SmallStep="1"
175+
Value="@SelectedPrice"
176+
ValueChanged="@((double v) => OnPriceChanged(v))">
177+
</TelerikSlider>
178+
</TelerikStackLayout>
179+
180+
@code {
181+
[Parameter] public double SelectedPrice { get; set; }
182+
[Parameter] public EventCallback<double> SelectedPriceChanged { get; set; }
183+
[Parameter] public FilterMenuTemplateContext Context { get; set; } = null!;
184+
185+
private async Task OnPriceChanged(double newValue)
186+
{
187+
SelectedPrice = newValue;
188+
Context.FilterDescriptor.FilterDescriptors.Clear();
189+
Context.FilterDescriptor.FilterDescriptors.Add(new FilterDescriptor(nameof(Product.Price), FilterOperator.IsGreaterThanOrEqualTo, newValue));
190+
await SelectedPriceChanged.InvokeAsync(newValue);
191+
}
192+
}
193+
`````
194+
`````RAZOR Product.cs
195+
public class Product
196+
{
197+
public int Id { get; set; }
198+
public string? Name { get; set; }
199+
public string? Size { get; set; }
200+
public double Price { get; set; }
201+
}
202+
`````
203+
## See Also
204+
205+
- [Grid Filter Templates](slug:grid-templates-filter)
206+
- [Filtering in Grid](slug:components/grid/filtering)

0 commit comments

Comments
 (0)