Elshad Shabanov
Elshad Shabanov

Reputation: 603

Blazored.FluentValidation: Validation won't work if I assign a new class instance to a form model

In my server-side Blazor app I have a TelerikForm, which is a wrapper around Blazor's EditForm. Form's model parameter is "vendor" For form validation I use Blazored.FluentValidation, which is registered as a Transient service. Validation works fine if I fill out all form fields manually. But in some scenarios, I need to fill all fields programmatically, assigning a new class instance to the "vendor" model: vendor = newVendor. In that case, the validator stops working. It seems that the validator doesn't recognize a new model. I think it is bound to the model's reference, and when the model changes its reference validator doesn't work anymore. However, if I assign model properties one by one, then it works fine, eg - vendor.Name = newVendor.Name.

How can I make a validator work with a new instance of the model?

Below is my code:

<TelerikForm Model="@vendor">
    <FormValidation>
        <FluentValidationValidator @ref="vendorValidator" DisableAssemblyScanning="true" />
    </FormValidation>
    <FormItems>
        <FormItem Field="@nameof(Vendor.TaxId)" />
        <FormItem Field="@nameof(Vendor.VendorName)" />
        <FormItem Field="@nameof(Vendor.CountryCode)" />
        <FormItem Field="@nameof(Vendor.CompanyWebsite)" />
        <TelerikValidationSummary />
    </FormItems>
    <FormButtons>
        <TelerikButton OnClick="@(() => ValidateVendor())">Submit</TelerikButton>
    </FormButtons>
</TelerikForm>


@code {
    Vendor? vendor = new();
    FluentValidationValidator? vendorValidator;

    bool ValidateVendor()
    {
        return vendorValidator.Validate(options => options.IncludeAllRuleSets());
    }

    void FillFormProgrammaticallyAndValidate(Vendor newVendor)
    {
        vendor = newVendor;
        ValidateVendor();

        // it works if I assign properties one by one
        // vendor.VendorName = newVendor.VendorName;
        // vendor.CountryCode = newVendor.CountryCode
    }

    public class VendorModelValidator : AbstractValidator<Vendor>
    {
        public VendorModelValidator()
        {
            RuleSet("ValidateName", () =>
            {
                RuleFor(p => p.VendorName)
                    .NotEmpty().WithMessage("'Name' is mandatory");
            });
        }
    }
}

sdsd

Upvotes: 3

Views: 3454

Answers (1)

dani herrera
dani herrera

Reputation: 51665

TelerikForm is the Telerik Blazor EditForm component, with the same parameters as a regular EditForm.

Technically, you can change model in EditForm and all will run fine if the component is rendered again:

@using System.ComponentModel.DataAnnotations

<EditForm Model="@exampleModel" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <InputText id="name" @bind-Value="exampleModel.Name" />

    <button type="submit">Submit</button>
</EditForm>

@exampleModel.Name

<button @onclick="ChangeModel">Change model</button>

@code {
    public class ExampleModel
    {
        [Required]
        [StringLength(10, ErrorMessage = "Name is too long.")]
        public string? Name { get; set; }
    }
    private ExampleModel exampleModel = new();
    private void HandleValidSubmit()
    {
    }
    protected void ChangeModel()
    {
        exampleModel = new();
        // At this point this component is rendered again
    }
}

If you take a look to EditForm source code, you can appreciate that is ready to deal with this scenario: "or if they are supplying a different Model":

        // Update _editContext if we don't have one yet, or if they are supplying a
        // potentially new EditContext, or if they are supplying a different Model
        if (Model != null && Model != _editContext?.Model)
        {
            _editContext = new EditContext(Model!);
        }

I don't know if you can do the same with TelerikForm because this is not an open source component. Open a ticket on Telerik and ask for it.

In any case, I recommend to you to avoid this practice and just assign new values to current model instead to change it. In my opinion, you should avoid changing the EditForm's model.

Also, you can notice that I posted a Minimum Reproducible Sample, you can copy-paste it, and it runs without issues. You should to learn about How to create a Minimal, Reproducible Example

Upvotes: 3

Related Questions