Blazored / FluentValidation

A library for using FluentValidation with Blazor
https://blazored.github.io/FluentValidation/
MIT License
597 stars 86 forks source link

[Question]: Is there any way I can find out which fields were valid and which were not? #201

Open john-dalsgaard opened 1 year ago

john-dalsgaard commented 1 year ago

I would like to save the valid fields on navigation as we allow the user to go back (and not be stuck) but would like to keep the data that is valid for when the user returns to the page.

I have tried a number of things like trying to read the validation messages:

editContext.GetValidationMessages();

or

var fld = editContext.Field(nameof(oneField));
var m = editContext.GetValidationMessages(fld);

But no success... Have I overlooked something?

Thanks in advance.

/John

Sharaf-Mansour commented 1 year ago

Hi @john-dalsgaard, The idea of validation itself. is that it prevent you from taking further actions if data is not valid. If you are doing SPA. And want to render another page or component you need to store the (State) of the old one. In the simplest form -> The default Counter Component that comes with Blazor template. resets its value on navigation. To store its state, you then need to use a (Scoped or Singleton) Service and inject it in the DI Container. That is the same thing with validation. You will need to store the state of the validation. And you can simple retrigger the Validation By using the Validate(item) And store it if it is valid and Ignore it if it is not.

@inject SomeService SomeService
@code
{
  void StoreValidItems(Foo item)
  {
     // Use the instance to validate. (Might need a validator for each item)
     bool IsValidFoo = new FooValidator().Validate(item).IsValid;
     // If Item is valid, Add it to your DI injected Service. Else? Ignore it!
     if(IsValidFoo) SomeService.ValidItems.Add(this);
   }
}

IMPORTANT NOTE!

Use NavigationManager to capture navigation events and store valid data in a separate object.

john-dalsgaard commented 1 year ago

Thanks for your reply. I do agree on the standard way of treating validation. As this is a survey where the user is allowed to go back and forth we do want to help storing the valid values if navigating back to a former subject and then return to the same page later.

The way I have set up validation at the moment is like this:

            <EditForm Model="@fishingDays" OnSubmit="@HandleValidation">
                <FluentValidationValidator @ref="_daysValidator" />
                        :
                        <InputNumber id="days1" @bind-Value="fishingDays.Angling" placeholder="@periodHint" />
                        <ValidationMessage For="@(() => fishingDays.Angling)" />
                        :
@code{
    private FishingDaysUI fishingDays = new();
    private EditContext daysContext;
    private FluentValidationValidator? _daysValidator;
    :

    protected override async Task OnParametersSetAsync()
    {
        :
        daysContext = new EditContext(fishingDays);
        StateHasChanged();
        await base.OnParametersSetAsync();
    }

    private async Task HandleValidation()
    {
        if (_daysValidator?.Validate() == true)
        {
            // Valid...
            StoreDays();
        }
        else
        {
            // Errors... Save those fields that are valid - but how to figure out??
            if (navigateForward) return;      // Just stop if trying to navigate forward
            StoreDays();
        }
        await Navigate(navigateTo);
    }

This is the current "compromise" where StoreDays() just check all of the fields prior to saving them - and it doesn't use the validation to figure out which fields are valid - essentially I have some duplicated logic that I would rather not have.... I just thought it would be cleaner to have one place to determine the rules for each field in the model.

In the above setup I don't use Dependency Injection. I cannot call the Validate() method for a field - as far as I can see the only parameter I can specify seems to be "options".

Well, I have a working solution now - so it is not a major issue any more... I was just wondering