Hi,
I was not sure if I had to create a separate topic for this question, or continue with this existing topic Inline editing on dynamic grid (that is one step before what I try to achieve) so I hope I made the good choice by creating one.
Basically, I have to work with dynamic data grids and I'm trying to bring as much features as possible.
I managed to make my dynamic datagrid work with inline editing thanks to the mentioned topic, but now I'm trying to add validation during edition/creation.
If I take back the example above, I would like for example to have a RadzenRequiredValidator on the firstname & lastname fields, to make sure that it's not empty while editing and existing row or creating a new row, but I can't figure out how to bind my validator to my component(RadzenTextBox) as it have dynamic names.
Thanks in advance for the help
enchev
March 11, 2025, 12:46pm
2
The "binding" is specifying the component name as Component property:
Yes but in this case the name is dynamic.
I tried to set it like this for example, but it's just reacting the same way as if there was no validator, so I guess I'm doing it wrong:
<EditTemplate>
<RadzenTextBox Name=@context[@column.Key].ToString() Value=@context[@column.Key].ToString() Change=@(value => @context[@column.Key] = value) />
<RadzenRequiredValidator Component=@context[@column.Key].ToString() Popup="true" Text="This column is mandatory." />
</EditTemplate>
enchev
March 11, 2025, 1:49pm
4
That expression will retrieve value - maybe you can use this column name simply.
That's also something I tried but the behavior stays the same:
<EditTemplate>
<RadzenTextBox Name=@column.Key Value=@context[@column.Key].ToString() Change=@(value => @context[@column.Key] = value) />
<RadzenRequiredValidator Component=@column.Key Popup="true" Text="This column is mandatory." />
</EditTemplate>
I also tried to hardcode the Name/Component by checking the column name directly in a "if" condition but it still does not work.
if (column.Key.Equals("MyKeyColumn"))
{
<RadzenTextBox Name="key" Value=@context[column.Key].ToString() style="width: 100%" Change=@(value => context[column.Key] = value) />
<RadzenRequiredValidator Component="key" Popup="true" Text="This column is mandatory." />
}
As far as i remember radzen validators works only with @bind-Value but i can be wrong.
Edit;
I found a mention about this here:
1 Like
enchev
March 11, 2025, 2:07pm
7
Ah good catch @GodzSky ! I've completely forgot about that - @bind-Value cannot work with complex expressions.
1 Like
Does this mean that validation is not possible with dynamic datagrid?
Or it can be done if I change the expression of "Value" to work with "@bind-Value "? If it's the case can someone help with the syntax? I don't know how this should be defined.
enchev
March 11, 2025, 3:44pm
9
In my opinion you can create custom component with a Value property, define this component in the EditTemplate and set the Value property and in the custom component itself you can use two way bind-Value binding.
enchev
March 12, 2025, 7:59am
10
Here is an example:
<RadzenDataGrid @ref=grid @bind-Value=@selectedItems Data="@data" TItem="IDictionary<string, object>" ColumnWidth="200px"
AllowFiltering="true" FilterPopupRenderMode="PopupRenderMode.OnDemand" FilterMode="FilterMode.Advanced" AllowPaging="true" AllowSorting="true">
<Columns>
@foreach (var column in columns)
{
<RadzenDataGridColumn @key=@column.Key Title="@column.Key" Type="column.Value"
Property="@PropertyAccess.GetDynamicPropertyExpression(column.Key, column.Value)">
<Template>
@context[@column.Key]
</Template>
<EditTemplate>
<DataGridDynamicDataEditComponent Name="@column.Key" Value="@($"{context[@column.Key]}")" />
</EditTemplate>
</RadzenDataGridColumn>
}
<RadzenDataGridColumn Width="100px" Context="data" Filterable="false" Sortable="false" TextAlign="TextAlign.Right" Frozen="true" FrozenPosition="FrozenColumnPosition.Right">
<Template Context="data">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="rz-my-1 rz-ms-1" Click="@(args => EditRow(data))" @onclick:stopPropagation="true" />
</Template>
<EditTemplate Context="data">
<RadzenButton Icon="check" ButtonStyle="ButtonStyle.Success" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@((args) => SaveRow(data))" aria-label="Save" />
<RadzenButton Icon="close" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="rz-my-1 rz-ms-1" Click="@((args) => CancelEdit(data))" aria-label="Cancel" />
</EditTemplate>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
@code {
RadzenDataGrid<IDictionary<string, object>> grid;
IList<IDictionary<string, object>> selectedItems;
public IEnumerable<IDictionary<string, object>> data { get; set; }
public IDictionary<string, Type> columns { get; set; }
public enum EnumTest
{
EnumValue1,
EnumValue2
}
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
columns = new Dictionary<string, Type>()
{
{ "Employee ID", typeof(int?) },
{ "MyColumn", typeof(EnumTest?) },
{ "FirstName", typeof(string) },
{ "LastName", typeof(string) },
{ "HireDate", typeof(DateTime?) },
{ "DateOnly", typeof(DateOnly?) },
{ "TimeOnly", typeof(TimeOnly?) },
{ "UID", typeof(Guid?) },
};
foreach (var i in Enumerable.Range(0, 50))
{
columns.Add($"Column{i}", typeof(string));
}
data = Enumerable.Range(0, 100).Select(i =>
{
var row = new Dictionary<string, object>();
foreach (var column in columns)
{
row.Add(
column.Key,
column.Value == typeof(EnumTest?)
? i == 0 ? null : (i % 2 == 0 ? EnumTest.EnumValue1 : EnumTest.EnumValue2)
: column.Value == typeof(int?)
? i == 0 ? null : i
: column.Value == typeof(DateTime?)
? i == 0 ? null : DateTime.Now.AddMonths(i)
: column.Value == typeof(Guid?)
? i == 0 ? null : Guid.NewGuid()
: column.Value == typeof(DateOnly?)
? i == 0 ? null : DateOnly.FromDateTime(DateTime.Now.AddMonths(i))
: column.Value == typeof(TimeOnly?)
? i == 0 ? null : TimeOnly.FromDateTime(DateTime.Now.AddMonths(i))
: $"{column.Key}{i}"
);
}
return row;
}).ToList();
}
List<IDictionary<string, object>> dataToUpdate = new List<IDictionary<string, object>>();
async Task EditRow(IDictionary<string, object> data)
{
if (!grid.IsValid) return;
dataToUpdate.Add(data);
await grid.EditRow(data);
}
async Task SaveRow(IDictionary<string, object> data)
{
await grid.UpdateRow(data);
}
void CancelEdit(IDictionary<string, object> data)
{
grid.CancelEditRow(data);
}
}
DataGridDynamicDataEditComponent.razor
<RadzenTextBox @bind-Value=@Value Name="@Name" />
<RadzenRequiredValidator Text="Required" Component="@Name" Popup="true" />
@code {
[Parameter]
public string Name { get; set; }
[Parameter]
public string Value { get; set; }
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
}
Thanks a lot for the example ! That's exactly what I needed
By using the component it seems like the display position of the popup is a bit weird but I could fix it by adding Style="display: block;" into the validator
<RadzenRequiredValidator Text="Required" Component="@Name" Popup="true" Style="display: block;" />
Cheers!