Blazor Form Items Overview
You can customize the default editors by using instances of the FormItem
tag. Those instances should be in the FormItems
collection.
In this article:
- FormItem parameters
- Combine explicit and autogenerated Form fields
- UI rendering and performance optimization inside the Form
FormItem Parameters
Each custom editor is expressed through the FormItem
tag. You can define a collection of those editors in the FormItems
tag that is a child of the TelerikForm
tag. You can find some code examples below.
The FormItem
tag exposes the following parameters which you can use to customize the editors:
LabelText
-string
- defines the label for the associated editor. This parameter provides more compact syntax for the<label for="myEditorId">
HTML tag.Id
-string
- maps to theid
HTML attribute of the<input>
tag.Hint
-string
- defines a hint for the user on the place of the validation message. If a validation error occurs the hint will be replaced by the corresponding validation message.Enabled
-bool
- whether the editor is enabled. Defaults totrue
. If it is not specifically defined in theFormItem
markup, it will take its value from the[Editable]
data annotation attribute of the item.Field
-string
- the name of the field in the model that the editor will render for as a string (case-sensitive). You can set its as a plain string (Field="SomeField"
) or to have .NET extract the field name from the model for flat models (Field=@nameof(MyModelClass.SomeFIeld)
). If you are using its Template to provide a custom editor, theField
parameter is not required.FieldType
-string
- the data type of theField
. This parameter should be provided if the type of the property in the model can not be extracted using reflection, for example it is anobject
and you would like to render aNumericTextBox
.ColSpan
-int
- defines thecolspan
attribute. This parameter is applicable when the FormItems are divided in multiple columns in a single group. See the FormGroups article for an example.Class
-string
- adds a custom CSS class to thek-form-field
div tag.Template
-RenderFragment
- allows you to change the default editor altogether. For more information see the Template article.
Example
@* Provide a hint and change the Label of the editors *@
@using System.ComponentModel.DataAnnotations
<TelerikForm Model="@person">
<FormValidation>
<DataAnnotationsValidator></DataAnnotationsValidator>
</FormValidation>
<FormItems>
<FormItem Field="@nameof(Person.Id)" Enabled="false" LabelText="Id"></FormItem>
<FormItem Field="@nameof(Person.FirstName)" LabelText="First name" Hint="Enter your first name"></FormItem>
<FormItem Field="@nameof(Person.LastName)" LabelText="Last name" Hint="Enter your last name" ColSpan="2"></FormItem>
<FormItem Field="@nameof(Person.DOB)" LabelText="Date of birth" Hint="Enter your Date of Birth"></FormItem>
</FormItems>
</TelerikForm>
@code {
public Person person = new Person();
public class Person
{
public int Id { get; set; } = 10;
public string FirstName { get; set; } = "John";
public string LastName { get; set; } = "Doe";
public DateTime DOB { get; set; } = DateTime.Today.AddYears(-20);
}
}
Add Form Fields to Autogenerated Ones
To combine manually defined with autogenerated fields, use an instance of the FormAutoGeneratedItems
tag inside the FormItems
collection.
@* Use the FormAutoGeneratedItems tag inside the FormItems to control the autogenerated fields position. *@
@using System.ComponentModel.DataAnnotations
<TelerikForm Model="@person">
<FormValidation>
<DataAnnotationsValidator></DataAnnotationsValidator>
</FormValidation>
<FormItems>
<FormItem Field="@nameof(Person.Id)" Enabled="false" LabelText="Id"></FormItem>
<FormItem Field="@nameof(Person.FirstName)" LabelText="First name" Hint="Enter your first name"></FormItem>
<FormAutoGeneratedItems></FormAutoGeneratedItems>
</FormItems>
</TelerikForm>
@code {
public Person person = new Person();
public class Person
{
public int Id { get; set; } = 10;
public string FirstName { get; set; } = "John";
public string LastName { get; set; } = "Doe";
public DateTime DOB { get; set; } = DateTime.Today.AddYears(-20);
}
}
UI Rendering inside the Form
When the user changes a value in a non-template Form item, the other Form items don't re-render. This default behavior serves as a performance optimization. In some scenarios, the app may need other form items to update too, for example:
- When the value in one Form item affects values in other Form items.
- When Form items show or hide, depending on the value in other Form items.
In such cases, there are a few ways to trigger re-rendering and UI refresh inside or outside the Form:
- Use a Telerik input component inside a Form item
<Template>
. - Call the
Refresh()
method of the Form. The method will re-render the Form itself. - Subscribe to the
OnUpdate
event of the Form. The event is anEventCallback
, so it will update the whole Razor component, which holds the Form. - Call
StateHasChanged()
inside the Razor component, which holds the Form. This will re-render the whole Razor component, including the Form.
<p>Type in the Form textboxes and observe the different results.</p>
<p>
<label>
<TelerikCheckBox @bind-Value="@ShouldUseOnUpdate" />
Use the <strong>Form <code>OnUpdate</code> event (an <code>EventCallback</code>)</strong> to re-render inside and outside the Form
</label>
</p>
<TelerikForm @ref="@FormRef"
Model="@Employee"
OnUpdate="@OnFormUpdate">
<FormItems>
<FormItem Field="@nameof(Person.Name)" LabelText="Regular FormItem - no re-render without OnUpdate"></FormItem>
<FormItem>
<Template>
<label class="k-label k-form-label" style="color:var(--kendo-color-success)">
FormItem with <code><Template></code> - re-render inside and outside the Form</label>
<div class="k-form-field-wrap">
<TelerikTextBox @bind-Value="@Employee.Name" DebounceDelay="0" />
</div>
</Template>
</FormItem>
<FormItem>
<Template>
<label class="k-label k-form-label" style="color:var(--kendo-color-warning)">
FormItem with Template and Form <code>Refresh()</code> - re-render inside the Form</label>
<div class="k-form-field-wrap">
<ChildComponent Value="@Employee.Name"
ValueExpression="@( () => Employee.Name )"
OnChange="@OnChildChange_Refresh" />
</div>
</Template>
</FormItem>
<FormItem>
<Template>
<label class="k-label k-form-label" style="color:var(--kendo-color-tertiary)">
FormItem with Template and <code>StateHasChanged()</code> - re-render inside and outside the Form</label>
<div class="k-form-field-wrap">
<ChildComponent Value="@Employee.Name"
ValueExpression="@( () => Employee.Name )"
OnChange="@OnChildChange_StateHasChanged" />
</div>
</Template>
</FormItem>
</FormItems>
</TelerikForm>
<br />
<p><code>Employee.Name</code> in UI outside the Form: <strong>@Employee.Name</strong></p>
<TelerikButton OnClick="@( () => { } )"
ButtonType="@ButtonType.Button">
Execute EventCallback - re-render inside and outside the Form
</TelerikButton>
@code {
private TelerikForm? FormRef { get; set; }
private Person Employee = new Person();
private bool ShouldUseOnUpdate { get; set; }
private EventCallback OnFormUpdate => ShouldUseOnUpdate ?
EventCallback.Factory.Create(this, OnFormUpdateHandler) :
default(EventCallback);
private void OnFormUpdateHandler()
{
// OnUpdate is an EventCallback.
// Blazor calls StateHasChanged() automatically to update the UI
// of the whole Razor component, which holds the Form.
}
private void OnChildChange_Refresh(string newValue)
{
Employee.Name = newValue;
if (!ShouldUseOnUpdate)
{
FormRef?.Refresh();
}
}
private void OnChildChange_StateHasChanged(string newValue)
{
Employee.Name = newValue;
if (!ShouldUseOnUpdate)
{
StateHasChanged();
}
}
protected override void OnInitialized()
{
Employee = new Person();
base.OnInitialized();
}
public class Person
{
public string Name { get; set; }
public Person()
{
Name = "John Doe";
}
}
}
@using System.Linq.Expressions
<TelerikTextBox Value="@Value"
ValueChanged="@TextBoxValueChanged"
ValueExpression="@ValueExpression"
DebounceDelay="0" />
@code {
[Parameter]
public string Value { get; set; } = string.Empty;
// This parameter is an Action instead of EventCallback.
// It doesn't refresh the whole parent component's UI,
// for example, for performance optimization.
[Parameter]
public Action<string>? OnChange { get; set; }
// Get a validation expression from a parent component.
// See https://docs.telerik.com/blazor-ui//blazor-ui/knowledge-base/inputs-validation-child-component
[Parameter]
public Expression<Func<string>>? ValueExpression { get; set; }
private void TextBoxValueChanged(string newValue)
{
Value = newValue;
OnChange?.Invoke(newValue);
}
}