Search code examples
validationblazorfluentvalidation

Blazor and fluentvalidation clear validation messages


I have a very simple model with a starttime and endtime:

public class OutputModel
{
   public event Action<double> OnStartChanged;
   public event Action<double> OnEndChanged;
   public double Start { get; private set; }
   public double End { get; private set; }
   public string StartProxy { get; set; }
   public string EndProxy { get; set; }
}

I'm using an EditForm to display inputboxes in which the user can edit these times. The inputboxes are bind to the StartProxy and EndProxy properties in such a way that I can trigger the events whenever a valid time is entered in either the start or end box.

<EditForm Model="@Model">
    <div class="m-2 selector">
        <FluentValidationValidator @ref="Model.Validator" />

        <div class="info-group mb-1">
            <label for="start">Start</label>
            <InputText id="start" class="form-control form-control-sm" Value="@Model.StartProxy" ValueChanged="Model.StartChanged" ValueExpression="() => Model.StartProxy" />
        </div>
        <ValidationMessage For="() => Model.StartProxy" />

        <div class="info-group mb-1">
            <label for="end">Einde</label>
            <InputText id="end" class="form-control form-control-sm" Value="@Model.EndProxy" ValueChanged="Model.EndChanged" ValueExpression="() => Model.EndProxy" />
        </div>
        <ValidationMessage For="() => Model.EndProxy" />

        <div class="info-group mb-1">
            <label for="duration">Duur</label>
            <input id="duration" disabled="true" class="form-control form-control-sm" @bind="Model.Duration">
        </div>
    </div>
</EditForm>

Doing this also requires me to validate things manually. So I have created 4 rulesets which I call manually when either StartProxy or EndProxy changes:

  1. A ruleset to check the format of StartProxy
  2. A ruleset to check the format of EndProxy
  3. A ruleset to check if Start is before End
  4. A ruleset to check if End is after Start

I have 3 and 4 because I want different messages at the startbox and endbox depending on the box that is currently used by the user.

The code that validates the start is this (the end is more or less the same, but different properties):

public void StartChanged(string value)
{
    StartProxy = value;
    var validator = new OutputModelValidator();

    // First check the format of the start
    var result = validator.Validate(this, options => options.IncludeRuleSets(OutputModelValidator.StartFormatRules));
    if (result.Errors.Any())
    {
        return;
    }

    // Start can be set if the format is ok
    Start = StartProxy.ToTimeSpan().Value.TotalSeconds;
    StartProxy = TimeSpan.FromSeconds(Start).ToString(TimeFormat);
    SetDuration();

    // Check if end is correct
    if (validator.Validate(this, options => options.IncludeRuleSets(OutputModelValidator.EndFormatRules)).Errors.Any())
    {
        // End contains errors, so were done here
        return;
    }

    // Start and end are 'format valid', now check their combination from an end perspective
    if (!validator.Validate(this, options => options.IncludeRuleSets(OutputModelValidator.StartBeforeEndRules)).Errors.Any())
    {
        // Start is good and end is good so propagate the values
        OnStartChanged?.Invoke(Start);
        OnEndChanged?.Invoke(End);
    }
}

So first I'm checking the format of the box that is changed. When valid I check if the 'other' box contains errors (because both can be wrong ofcourse). When good, then I check the combination for start and end.

In basic this works fine, but the problem is the following:

  1. The endbox shows: '00:25.200'
  2. I type '00:30.123' in the startbox
  3. The code validates and gives an error at the startbox: 'Start not after end'
  4. I now type '00:35.200' in the endbox
  5. The code validates and everything is fine.
  6. My startbox still shows the message: 'Start not after end'

So my question is: how can I clear the messages for the 'other' property. Or do I need a completely different approach. Suggestions are welcome ofcourse.

Many thanks in advance


Solution

  • After searching and searching and much more searching (and finding the answers in this thread: How to reset custom validation errors when using editform in blazor razor page) I finally was able to fix this.

    First problem was my binding to the editform. I had this:

    <EditForm Model="@Model">
    

    which should be this:

    <EditForm EditContext="@Model.EditContext">
    

    Then in the code after all the validations are done I now call this:

    EditContext.NotifyFieldChanged(new FieldIdentifier(this, nameof(StartProxy)));
    

    So you tell Blazor to update the other field (in this case StartProxy).