bruceiow
bruceiow

Reputation: 83

Fluent Validator in Blazor - Trigger Validation After Component Value Update

This question is regarding a Blazor Server Application using the Blazor Fluent Validation package.

I have created a component that is effectively a numeric text box field that enforces values to be double. The component takes three parameters. The value of the model item, the maximum value the field can accept and the minimum value the field can accept. The parent page looks like this:

<DoubleNumericOnly @bind-Data="@MyModel.DAmount" Min="50" Max="4000"/>

I need the child component to be able to validate that the bound data value is between the Min and Max values. The Min and Max attributes are optional.

My initial thought was to allow the parent page to handle to validation using this decalration inside my edit form:

<Blazored.FluentValidation.FluentValidationValidator></Blazored.FluentValidation.FluentValidationValidator>

With the message shown in the normal way:

<ValidationMessage For="() => MyModel.DAmount"></ValidationMessage> 

My problem lies in the fact that the Min and Max values are dynamic for each instance of the DoubleNumericOnly component I put on the page e.g:

<DoubleNumericOnly @bind-Data="@MyModel.DAmount" Min="50" Max="4000"/>
<DoubleNumericOnly @bind-Data="@MyModel.AnotherDAmount" Min="100" Max="400"/>

Is there a way that I can let FluentValidator know for each property what those dynamic Min and Max figures should be?

If I can do that, I wondered if I could pass the responsibility of validation to the component itself. I struggled with this as fluent seems to kick off its validation on submit. I would need to figure a way of triggering the validation when the value of the field has been changed. I searched the Fluent documentation but was unable to find a way of doing this.

Any tips greatly appreciated.

Upvotes: 1

Views: 1585

Answers (1)

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30410

As your validation is "component" based rather than field based, it needs to be implemented in the component.

Here's a derived version of InputNumber that's fixed for double and does the checking in TryParseValueFromString.


public class InputDouble : InputNumber<double>
{
    [Parameter] public double? Min { get; set; }
    [Parameter] public double? Max { get; set; }

    // Overrides the default handler.
    // This is the code lifted from the base with the additional checks added for Min and Max
    protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out double result, [NotNullWhen(false)] out string? validationErrorMessage)
    {
        if (BindConverter.TryConvertTo<double>(value, CultureInfo.InvariantCulture, out result))
        {
            if (Min is not null && result < this.Min)
            {
                validationErrorMessage = $"{DisplayName ?? FieldIdentifier.FieldName} must be greater than {this.Min} ";
                return false;
            }

            if (Max is not null && result > this.Max)
            {
                validationErrorMessage = $"{DisplayName ?? FieldIdentifier.FieldName} must be less than {this.Max} ";
                return false;
            }

            validationErrorMessage = null;
            return true;
        }
        else
        {
            validationErrorMessage = string.Format(CultureInfo.InvariantCulture, ParsingErrorMessage, DisplayName ?? FieldIdentifier.FieldName);
            return false;
        }
    }
}

And a demo:

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

<EditForm EditContext="_editContext">
    <InputDouble class="form-control" @bind-Value=_model.Value Max="100" Min="0" />
    <ValidationMessage For="() => _model.Value" />
</EditForm>

@code {
    private Model _model = new();
    private EditContext? _editContext;

    protected override void OnInitialized()
    {
        _editContext = new(_model);
    }

    public class Model
    {
        public double Value { get; set; }
    }
}

Upvotes: 1

Related Questions