Validate a Telerik component as child component and apply invalid border
Environment
Product |
AutoComplete for Blazor, ComboBox for Blazor, DatePicker for Blazor, DateTimePicker for Blazor, DropDownList for Blazor, MultiColumnComboBox for Blazor, MultiSelect for Blazor, TimePicker for Blazor |
Description
I am wrapping a Telerik component inside a custom component in my Form. When I try to validate it, the red invalid border does not appear.
Solution
Internally, the Telerik input components use the cascading EditContext
parameter that the EditForm
and TelerikForm
provide. The EditContext
API allow the components to determine if validation has passed or failed. If the validation fails, the components show a red border.
When you wrap an input component in a custom child component, you must define a ValueExpression
parameter for the child component. This allows the child component to receive the correct expression from the parent component, which holds the Form. The Blazor framework generates the expression automatically when using @bind-Value
, but not when there is another component in the component hierarchy tree.
The example below shows how to wrap a Telerik TextBox and DropDownList in different .razor
files and get the invalid red border when the validation does not pass. Note the different For
parameter syntax in the two <TelerikValidationMessage />
instances in Home.razor
and DropDownList.razor
. The For
syntax depends on whether the TelerikValidationMessage
component is in the same component as the Form, or in a child component, which consumes a ValueExpression
parameter.
Validate a TextBox and a DropDownList in custom components with ValueExpression parameters
@using System.ComponentModel.DataAnnotations
<TelerikForm Model="@CustomerToEdit"
OnValidSubmit="@OnFormValidSubmit"
Width="300px">
<FormValidation>
<DataAnnotationsValidator></DataAnnotationsValidator>
<TelerikValidationSummary />
</FormValidation>
<FormItems>
<FormItem Field="@nameof(Customer.Id)" Enabled="false" LabelText="ID`" />
<FormItem Field="@nameof(Customer.Name)">
<Template>
<label for="customer-name" class="k-label k-form-label">Name</label>
<div class="k-form-field-wrap">
<TextBox @bind-Value="@CustomerToEdit.Name"
Id="customer-name" />
<TelerikValidationMessage For="@(() => CustomerToEdit.Name)" />
</div>
</Template>
</FormItem>
<FormItem Field="@nameof(Customer.CountryId)">
<Template>
<label for="customer-countryid" class="k-label k-form-label">Country</label>
<div class="k-form-field-wrap">
<DropDownList Data="@Countries"
@bind-Value="@CustomerToEdit.CountryId"
TextField="@nameof(Country.Name)"
ValueField="@nameof(Country.Id)"
Id="customer-countryid" />
@* TelerikValidationMessage is in DropDownList.razor *@
</div>
</Template>
</FormItem>
</FormItems>
</TelerikForm>
<p style="color:var(--kendo-color-success)"><strong>@FormSubmitResult</strong></p>
@code {
private Customer CustomerToEdit { get; set; } = new();
private List<Country> Countries { get; set; } = new();
private string FormSubmitResult { get; set; } = string.Empty;
private void OnFormValidSubmit()
{
FormSubmitResult = $"Form Submit Success at {DateTime.Now.ToString("HH:mm:ss")}";
}
protected override void OnInitialized()
{
Countries = new()
{
new() { Id = 1, Name = "Australia" },
new() { Id = 2, Name = "Bulgaria" },
new() { Id = 3, Name = "Germany" },
new() { Id = 4, Name = "India" },
new() { Id = 5, Name = "UK" },
new() { Id = 6, Name = "USA" }
};
}
}