In a Blazor form, ValidationMessage displays validation errors for one model property. Its For parameter identifies that property with a parameterless expression. Use it beside the corresponding input when a form-wide ValidationSummary is not specific enough. section 36.2.2
Show errors for a firstname
Inside an EditForm with Model="PersonData", place <ValidationMessage For="@(() => PersonData.Firstname)" /> beside an InputText bound to PersonData.Firstname. The expression selects a property on the model object, not on the Person type. With DataAnnotationsValidator in the form, validation attributes on Firstname provide the messages. section 36.2.2
Two practical checks:
- If Blazor cannot determine the selected property's type and throws an exception, specify it explicitly—for example, TValue="long" for a long property. section 36.2.2
- Style div.validation-message to make property-level errors visible; validation classes can also distinguish edited valid and invalid inputs. section 36.2.2
Do not confuse this capitalized Blazor parameter with other for attributes: a partial element uses for to select a partial view's model, while an HTML label's for associates it with an input. section 22.5.3 section 27.5
Listing 36.11 Applying validation in the Editor.razor file in the Blazor/Forms folder
@page "/forms/edit/{id:long}"
@layout EmptyLayout
<link href="/blazorValidation.css" rel="stylesheet" />
<h4 class="bg-primary text-center text-white p-2">Edit</h4>
<FormSpy PersonData="PersonData">
<EditForm Model="PersonData">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-group">
<label>Person ID</label>
<InputNumber class="form-control"
@bind-Value="PersonData.PersonId" disabled />
</div>
<div class="form-group">
<label>Firstname</label>
<ValidationMessage For="@(() => PersonData.Firstname)" />
<InputText class="form-control"
@bind-Value="PersonData.Firstname" />
</div>
<div class="form-group">
<label>Surname</label>
<ValidationMessage For="@(() => PersonData.Surname)" />
<InputText class="form-control"
@bind-Value="PersonData.Surname" />
</div>
<div class="form-group">
<label>Dept ID</label>
<ValidationMessage For="@(() => PersonData.DepartmentId)" />
<CustomSelect TValue="long" Values="Departments"
Parser="@((string str) => long.Parse(str))"
@bind-Value="PersonData.DepartmentId">
<option selected disabled value="0">
Choose a Department
</option>
</CustomSelect>
</div>
<div class="form-group">
<label>Location ID</label>
<ValidationMessage For="@(() => PersonData.LocationId)" />
<CustomSelect TValue="long" Values="Locations"
Parser="@((string str) => long.Parse(str))"
@bind-Value="PersonData.LocationId">
<option selected disabled value="0">
Choose a Location
</option>
</CustomSelect>
</div>
<div class="text-center">
<NavLink class="btn btn-secondary mt-2" href="/forms">
Back
</NavLink>
</div>
</EditForm>
</FormSpy>
@code {
// ...members omitted for brevity...
}
See the validation components, property-specific message, and bound input together in the form. section 36.2.2
