Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blazor EditContext : How to check validation message for nested object

I have an extension method to check if a specific field is valid or not.

        public static bool IsValid(this EditContext editContext, string fieldName)
        {
            var fieldIdentifier = editContext.Field(fieldName);

            editContext.NotifyFieldChanged(fieldIdentifier);

            var result = !editContext.GetValidationMessages(fieldIdentifier).Any();

            Console.WriteLine($"{fieldName}  : {result}");

            return result;
        }

It's working fine for non-complex fields but not for complex fields. e.g

My model is

    public class RegisterCompanyRequest
    {
        [Required(ErrorMessage = "Company Name is required")]
        [MaxLength(200, ErrorMessage = "Maximum allowed length for company name is 200 characters")]
        public string NameEn { get; set; }

        [ValidateComplexType]
        public List<CompanyLocation> CompanyLocations { get; set; }

        [ValidateComplexType]
        public CompanyAdminInfo CompanyAdminInfo { get; set; } = new CompanyAdminInfo();
    }

    public class CompanyAdminInfo
    {
        [Required(ErrorMessage = "Full name is required")]
        [MaxLength(200, ErrorMessage = "Maximum allowed length for full name is 200 characters")]
        public string FullName { get; set; }
    }

    public class CompanyLocation
    {
        public int Id { get; set; }

        [Required]
        [MaxLength(200, ErrorMessage = "Maximum allowed length for location name is 200 characters")]
        public string Name { get; set; }
    }

and if I pass that method NameEn it returns false if validation fails and true otherwise, but if i pass it CompanyLocations[0].Name or CompanyAdminInfo.FullName it always return true.

How can I achieve the same functionality for nested objects in my Model?

To Reproduce: Copy the below code to new blazor WASM project. also install the following package to validate complex type (Install-Package Microsoft.AspNetCore.Components.DataAnnotations.Validation -Version 3.2.0-rc1.20223.4)

@page "/"
@using System.ComponentModel.DataAnnotations

<p>"Name" : @company.Name <span>@nameValid</span> </p> 
<p>"Admin Name" : @company.Admin.Name <span>@adminNameValid</span> </p>

<EditForm EditContext="editContext">
    <ObjectGraphDataAnnotationsValidator />

    <input type="text" @bind-value="@company.Name"/>

    <input type="text" @bind-value="@company.Admin.Name"/>

    <button @onclick="Validate" type="submit">Validate</button>
</EditForm>


@code
{
    private bool nameValid, adminNameValid;
    private Company company = new Company();

    EditContext editContext { get; set; }

    protected override async Task OnInitializedAsync()
    {
        editContext = new(company);
    }

    private async Task Validate()
    {
        var isValid = IsValid(editContext, "Name");

        nameValid = isValid;

        isValid = IsValid(editContext, "Admin.Name");

        adminNameValid = isValid;
    }

    public bool IsValid(EditContext editContext, string fieldName)
    {
        var fieldIdentifier = editContext.Field(fieldName);

        editContext.NotifyFieldChanged(fieldIdentifier);

        return !editContext.GetValidationMessages(fieldIdentifier).Any();
    }

    public class Company
    {
        [Required]
        public string Name { get; set; }

        [ValidateComplexType] /*(Install-Package Microsoft.AspNetCore.Components.DataAnnotations.Validation -Version 3.2.0-rc1.20223.4)*/
        public Admin Admin { get; set; } = new Admin();
    }

    public class Admin
    {
        [Required]
        public string Name { get; set; }
    }

}
like image 737
Zubair Khakwani Avatar asked Apr 28 '26 05:04

Zubair Khakwani


1 Answers

I guess, do you have two antipatterns in your code.

First one is to call, by hand, editContext.NotifyFieldChanged(fieldIdentifier);. Let Blazor deal with notifications.

The second one is with Submit, in my opinion, you should to avoid calling functions on submit button. Instead of that, use OnValidSubmit or OnInvalidSubmit at EditForm component level, or bind a function to editContext.OnValidationStateChanged like in my running sample bellow.

@page "/"
@using System.ComponentModel.DataAnnotations
@implements IDisposable

<EditForm EditContext="editContext" OnValidSubmit="ValidSubmit">
    
    <ObjectGraphDataAnnotationsValidator />
    
    <InputText type="text" @bind-Value="@company.Name" />
    <ValidationMessage For="@(() => company.Name)" />

    <InputText type="text" @bind-Value="@company.Admin.Name" />
    <ValidationMessage For="@(() => company.Admin.Name)" />
    
    <button type="submit">Validate</button>
    
</EditForm>

<p>"Name" : @company.Name <span>@nameValid</span> </p> 
<p>"Admin Name" : @company.Admin.Name <span>@adminNameValid</span> </p>

@code
{
    private bool? nameValid, adminNameValid;
    private Company company = new Company();

    EditContext editContext { get; set; } = default!;

    protected override void OnInitialized()
    {
        editContext = new(company);
        editContext.OnValidationStateChanged += HandleValidationStateChanged;
    }

    private void HandleValidationStateChanged(object? o, ValidationStateChangedEventArgs args) 
    {
        var name_field = FieldIdentifier.Create( () => company.Name  );
        nameValid = IsValid(editContext, name_field);

        var admin_name_field = FieldIdentifier.Create( () => company.Admin.Name  );
        adminNameValid = IsValid(editContext, admin_name_field);

    }

    private void ValidSubmit()
    {
        nameValid = true;
        adminNameValid = true;
    }

    public bool IsValid(EditContext editContext, FieldIdentifier fieldIdentifier)
        =>
        !editContext.GetValidationMessages(fieldIdentifier).Any();

    public class Company
    {
        [Required]
        [StringLength(3, ErrorMessage = "Identifier too long (3 character limit).")]
        public string Name { get; set; } = default!;

        [ValidateComplexType] /*(Install-Package Microsoft.AspNetCore.Components.DataAnnotations.Validation -Version 3.2.0-rc1.20223.4)*/
        public Admin Admin { get; set; } = new Admin();
    }

    public class Admin
    {
        [Required]
        [StringLength(3, ErrorMessage = "Identifier too long (3 character limit).")]
        public string Name { get; set; } = default!;
    }

    public void Dispose()
    {
        if (editContext is not null)
        {
            editContext.OnValidationStateChanged -= HandleValidationStateChanged;
        }
    }

}
like image 75
dani herrera Avatar answered Apr 30 '26 19:04

dani herrera



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!