Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate a model in Blazor server app without triggering validation messages?

I'm working on a Blazor server app where user information is collected in several steps. Parent page creates a model(let's call it MainModel), which is a collection of data from models used in child components, parent passes this model to children as a cascading parameter and children collect more info and fill in matching parameters in that model.

When the component is loaded, it loads its own model. When an input is modified, I need to check ChildModel and add it to MainModel if it passes the validation. Based on Blazor documentation, I used FieldChanged event for EditContext.


    <EditForm EditContext="editContext">
    <DataAnnotationsValidator/>
    <div class="col-md-6">
        <label for="FirstName" class="form-label">First Name</label>
        <InputText type="text" @bind-Value="Model.FirstName" class="form-control" 
     name="FirstName"/>
        <ValidationMessage For="@(() => Model.FirstName)" />
    </div>
    <div class="col-md-3">
        <label for="LastName" class="form-label">Last Name</label>
        <InputText type="text" @bind-Value="Model.LastName" class="form-control" 
        name="LastName"/>
        <ValidationMessage For="@(() => Model.LastName)" />
    </div>

    <div class="col-md-3">
        <label for="Age" class="form-label">Age</label>
        <InputText type="text" @bind-Value="Model.Age" class="form-control" name="Age"/>
        <ValidationMessage For="@(() => Model.Age)" />
    </div>
    </EditForm>


    @code{
    [CascadingParameter]
    public MainModel MainModel { get; set; }

    private ChildModel Model {get; set; }


    private EditContext editContext;

    protected override async Task OnInitializedAsync()
    {
        editContext = new EditContext(Model);
        editContext.OnFieldChanged += EditContext_OnFieldChanged;
        base.OnInitialized();
    }

    private async void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
    {
        if(editContext.Validate()) //<-- this shows validation messages
        {
            //copy child model to main model here
        }
    }
}

The problem is, as soon as a field is modified, this event is fired, as expected, and the model is validated which fires up the validation messages for all inputs because at that point none of the other required fields are filled in.

Is there a way to validate a model without triggering validation messages?

Maybe I need to do something with ValidationMessageStore but I haven't figured it out yet. I can toggle individual validation messages by looking at their input sibling's modified and invalid classes but I'm sure Blazor has a solution for this.

So far I don't have an answer for it so my current implementation is this:

When the EditContext.Validate() is called, I'm hiding the messages with css initially and show them only when inputs are modified and invalid:

.validation-message {
  display: none; 
}

input.modified.invalid {
  border: 1px solid red;
  position: relative; 
}

input.modified.invalid + .validation-message {
    position: absolute;
    margin-top: -10px;
    color: red;
    background: #fdf2f2;
    border: 1px solid #ffdede;
    padding: 5px;
    display: block;
    z-index: 1; 
}
like image 580
PersyJack Avatar asked Oct 28 '25 01:10

PersyJack


2 Answers

Not a direct answer, but Chris Sainty has created a blazor wrapper for the FluentValidator @AliK referred to. Very elegant solution he describes in his book and blog. Much simpler than rolling your own.

  1. Add his Blazored Nuget package

dotnet add package FluentValidation

  1. Insert his component inside your EditForm replacing the weaker DataAnnotationsValidator:

<FluentValidationValidator @ref="fluentValidationValidator" />

  1. Create a variable to hold the validator reference:

private FluentValidationValidator fluentValidationValidator;

  1. Setup fluent validations for your child model. Really powerful tool that has been around for a while. I have been able to setup complex record level validations, duplicate checks, etc.

  2. Now you can validate in code quite easily:

    var isValid = fluentValidationValidator.Validate(opts => opts.IncludeAllRuleSets());
    if (!isValid) return;  // show errors
    // else, proceed
    
like image 54
Steve Greene Avatar answered Oct 29 '25 17:10

Steve Greene


What I usually do is have a bool variable that captures whether or not the editContext is valid. Something like prive bool _modelHasBeenModified {get; set;} = false;

Then I'll run the validation _modelHasBeenModified = editContext.Validate();

Then I'll reset the validations so none of the validation messages are displayed: editContext.MarkAsUnmodified(); - this way, I can still retain the model validity in _modelHasBeenModified.

like image 20
sion_corn Avatar answered Oct 29 '25 17:10

sion_corn