Hi, in a my application I save the filters to db, and I permit the user to edit this.
The ValueTemplate (in FilterField component) works perfectly on insert, but not when I update the value of an existing FilterDescriptor (the CompositeFilterDescriptor is not updated).
I've gone deeper, and I think that missing a call to FilterChanged method in the TelerikFilter (from the child).
When the TelerikFilter render a FilterField this set the FilterChanged method that is used any time that you change something in the filter, but with a custom component this call missing.
I think that you must expose the FilterChanged (that now is private) or in TelerikFilter, or better in in context (FilterFieldValueTemplateContext) that you use in the FilterField.ValueTemplate, to force the update in the parent component.
To test this, you can use your code in https://blazorrepl.telerik.com/wIuhlcYV35fUROFX47 and add a new FilterDescriptor in the OnInitialized method, or you can test it with the code below (based on your own).
@using Telerik.Blazor.Components
@using Telerik.DataSource
@using Telerik.DataSource.Extensions
@{
var firstFilter = (Telerik.DataSource.FilterDescriptor?)FilterValue?.FilterDescriptors.FirstOrDefault();
if (firstFilter is not null)
{
<div>
firstFilter value: @firstFilter.Value
</div>
}
}
<TelerikFilter Value="@FilterValue" ValueChanged="@OnValueChanged">
<FilterFields>
@foreach (var f in FilterFields)
{
if (nameof(Food.Price) == f.Name)
{
<FilterField Name="@f.Name" Type="@f.Type" Label="@f.Label" >
<ValueTemplate>
<TelerikNumericTextBox Value="@((decimal?)context.FilterDescriptor.Value)"
ValueChanged="@( (decimal? value) => NumericValueChanged(context.FilterDescriptor, value) )">
</TelerikNumericTextBox>
</ValueTemplate>
</FilterField>
}
else
{
<FilterField Name="@f.Name" Type="@f.Type" Label="@f.Label" />
}
}
</FilterFields>
</TelerikFilter>
<TelerikGrid Data="@GridData"
Height="400px">
<GridColumns>
<GridColumn Field="@(nameof(Food.Id))" />
<GridColumn Field="@(nameof(Food.Name))" />
<GridColumn Field="@(nameof(Food.Price))" />
<GridColumn Field="@(nameof(Food.IsAvailable))" />
</GridColumns>
</TelerikGrid>
@code {
private List<Food> GridData { get; set; } = new();
private List<Food> InitialData { get; set; } = new();
private CompositeFilterDescriptor FilterValue { get; set; } = new();
private List<string> Suggestions { get; set; } = new() { "Pasta", "Burger", "Pizza", "Kebab", "Steak", "Ice Cream" };
private void OnFilterValueChanged(FilterDescriptor fd, string value)
{
fd.Value = value;
ProcessGridData();
}
private void NumericValueChanged(FilterDescriptor fd, decimal? value)
{
fd.Value = value;
var a = FilterValue;
ProcessGridData();
}
private void OnValueChanged(CompositeFilterDescriptor value)
{
FilterValue = value;
ProcessGridData();
}
private void ProcessGridData()
{
CompositeFilterDescriptor filter = FilterValue;
var dataSourceRequest = new DataSourceRequest { Filters = new List<IFilterDescriptor> { filter } };
var dataSourceResult = InitialData.ToDataSourceResult(dataSourceRequest);
GridData = dataSourceResult.Data.Cast<Food>().ToList();
}
protected override void OnInitialized()
{
FilterValue.FilterDescriptors.Add(new FilterDescriptor { Member = nameof(Food.Price), Operator = FilterOperator.IsEqualTo, Value = Convert.ToDecimal(0), MemberType = typeof(decimal) });
LoadData();
base.OnInitialized();
}
private void LoadData()
{
InitialData = new List<Food>
{
new Food { Id = 1, Name = "Pasta", Price = 13.99m, IsAvailable = true},
new Food { Id = 2, Name = "Burger", Price = 11.99m, IsAvailable = false},
new Food { Id = 3, Name = "Pizza", Price = 16.99m, IsAvailable = true},
new Food { Id = 4, Name = "Kebab", Price = 9.99m, IsAvailable = true },
new Food { Id = 5, Name = "Steak", Price = 22.99m, IsAvailable = false },
new Food { Id = 6, Name = "Salad", Price = 6.99m, IsAvailable = true},
new Food { Id = 6, Name = "Ice Cream", Price = 4.99m, IsAvailable = true }
};
ProcessGridData();
}
public class Food
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public bool IsAvailable { get; set; }
}
public List<MyFilterField> FilterFields = new List<MyFilterField>
{
new MyFilterField { Name = nameof(Food.Price), Type = typeof(double?), Label = "Price" },
new MyFilterField { Name = nameof(Food.Id), Type = typeof(int), Label = "Id" },
new MyFilterField { Name = nameof(Food.Name), Type = typeof(string), Label = "Name" },
new MyFilterField { Name = nameof(Food.IsAvailable), Type = typeof(bool), Label = "Is Available" }
};
public class MyFilterField
{
required public string Name { get; set; }
required public Type Type { get; set; }
required public string Label { get; set; }
}
}
Hello,
I created a repl to replicate the issue that I'm having. I created a Filter with a custom editor. For this example, I used a Textbox and I save the changes back to the context.FilterDescriptor.Value in the OnChange method which occurs when the user blurs focus.
If you start the repl w/o checking the Use Custom Editor checkbox and enter text where the "Sample" value is located you will see the changes are saved properly to the bound CompositeFilter property and are echo'd back in the screen.
If instead you check the Use Custom Editor box and perform the same test you'll see that the same changes are not present in the bound CompositeFilter.
Note that this issue only occurs if you start with an existing CompositeFilter and bind it to the filter control. It seems that if the control creates the FilterDescriptor objects then their changes bind properly, but if the FilterDescriptor objects existed before binding to the control then the issue occurs.
https://blazorrepl.telerik.com/wIOtcKOb31mjTc3351
Thank You,
-Andy
Please expose a refresh/rebind method for the Filter. I want to force refresh the component when programmatically changing its value during runtime.
===
ADMIN EDIT
===
A possible workaround for the time being is to dispose the component and reinitialize it again after programmatically changing the value. Here is an example: https://blazorrepl.telerik.com/GnkgQPPU37sHWkak55.
When I change the field from the dropdown to another field of the same type, the filter editor is not updated.
The issue occurs when I'm using Enum fields - the dropdown editor is not updated to display the correct values of the newly selected Enum field.
Reproduction: https://blazorrepl.telerik.com/QHExPalR55jvaD1t12.
Steps to reproduce:
I'd like to be able to change the default editor of the filter field. For example, for DateTime fields, I want to use DateTimePicker instead of the default DatePicker.
Please expose an option to customize that similar to https://docs.telerik.com/blazor-ui/components/grid/filter/overview#customize-the-filter-editors.
I want my users to be able to add only one level of groups to their filters. I want to remove the "Add Group" button in the second level toolbar.
===
ADMIN EDIT
===
For the time being, such a result can be achieved with CSS. You can target and hide the "Add Group" button of the desired level to prevent the user from creating another nested group.
Steps to reproduce:
Can the ability to define a height/width for the Filter component be exposed?
Width - I've noticed that if your Column names are to long names are cut off. I've used CSS to work around this.
Height - This isn't exactly a bug but if you populate enough "<FilterField/>" the dropdownlist will extend down past the bottom of the page.
It would be helpful if we can we can define more settings from the dropdownlists Or atleast make it so the dropdownlist will not go beyond the bottom of the page.
I would like to request an ability to add a dropdown of available values so that a user could select one or more items on the value side.
For Example:
User selects "Room Type" for Filter Name and is presented with "Queen", "King", "Double". The user would then be able to select one or more of those values. This would replace a multitude of "OR" statements, in additional; it could make finding things easier by knowing what values I can search for.
Possibly apply a "Template" for the value of a Filter Name. Purely as a concept:
<TelerikFilter Value="@Value" ValueChanged="@OnValueChanged">
<FilterFields>
<FilterField Name="@nameof(OrderDetailDto.OrderId)" Type="typeof(int)" Label="Id" />
<FilterField Name="@nameof(OrderDetailDto.Quantity)" Type="typeof(short)" />
<FilterField Name="@nameof(OrderDetailDto.OrderFreight)" Type="@typeof(decimal)" Label="Freight" />
<FilterField Name="@nameof(OrderDetailDto.OrderShipCountry)" Type="typeof(string)" Label="Country">
<FilterValueTemplate>{{Some Template Here}}</FilterValueTemplate>
</FilterField>
<FilterField Name="@nameof(OrderDetailDto.OrderShipName)" Type="typeof(List<string>)" Label="Ship to">
<FilterValueTemplate>{{Some Template Here}}</FilterValueTemplate>
</FilterField>
<FilterField Name="@nameof(OrderDetailDto.OrderShipAddress)" Type="typeof(string)" Label="Ship Address" />
</FilterFields>
</TelerikFilter>
If the CompositeFilterDescriptor is set with a predefined filter before the filter component is rendered on the page it locks up the UI.
I've noticed this issue if the Filter is user under a TabStrip.. You set the filter and navigate way from the tab and back it will lock up.
I would like to limit how many nested groups in the Filter the user can make.
It would be nice to have events raised when filters are added. This will allow me to use my own logic (e.g., to ensure something exists before adding/removing another).