blazor - EditForm Validation With List of Model Rather Than Single Model - Stack Overflow

Single Model (Validates As Expected)I have created an EditForm in Blazor where I was able to easily ad

Single Model (Validates As Expected)

I have created an EditForm in Blazor where I was able to easily add validation for a single model where I added OnValidSubmit to the form with the DataAnnotationsValidator and ValidationSummary tags at the top:

<EditForm FormName="CriminalConvictions" Model="criminalConvictions" OnValidSubmit="SubmitMany">
    <DataAnnotationsValidator />
    <ValidationSummary />

This is the model declaration where is instantiates a new instance of the model:

[SupplyParameterFromForm]
public CriminalConvictionModel? criminalConviction { get; set; }

protected override async Task OnInitializedAsync()
{
    criminalConviction ??= new();
}

Then I can add in the validation message under the field as well:

<InputTextArea @bind-Value="criminalConviction!.Offence" class="form-control" />
<ValidationMessage For="@(() => criminalConviction!.Offence)" />

And in the model class I can then add a required tag to require a value for this field:

public class CriminalConvictionModel
{
    public int CriminalConvictionID { get; set; }
    public DateTime? DateOfOffence { get; set; }

    [Required(ErrorMessage = "Please record details of the offence")]
    public string? Offence { get; set; }
    
    ...
}

This all works and validates the field as expected:

List of Model (Won't Validate)

However I now need to allow multiple items to be submitted so changed the model declaration to be a list of model objects like this:

public CriminalConvictionModel? criminalConviction { get; set; }
[SupplyParameterFromForm]
public List<CriminalConvictionModel>? criminalConvictions { get; set; }

protected override async Task OnInitializedAsync()
{
    criminalConviction ??= new();
    criminalConvictions = new List<CriminalConvictionModel>();
    criminalConvictions?.Add(criminalConviction);
}

Then I changed the submit function to save a list of models to the database which works and saves the records to the SQL database but the validation no longer works as this required field can now be left blank and it is not picked up and OnValidSubmit is being executed regardless of if the models in the list are valid or not.

If the EditForm model is set as the single criminalConviction then it validates the first set of elements but not subsequent ones but if I set it as the list I declared which is criminalConvictions then no validation occur and I can't work out what I need to change to make it work.

This is the function I added to add new models to the list of models to add a new set of form fields:

private void AddMoreConvictions() {
    formSubmitted = false;

    CriminalConvictionModel newConviction = new CriminalConvictionModel();
    criminalConvictions = new List<CriminalConvictionModel>();

    criminalConvictions?.Add(newConviction);
}

So it all works and saves multiple records to the database but I just can't work out how to get validation working for List<Model> when it works as expected for Model and I can't work out what I am missing and also ideally it would be better if the validation summary could be per list of fields so it is clear which set has the missing field.

Other Approaches Attempted

The most obvious approach to this from looking online is to use ObjectGraphDataAnnotationsValidator, which seems to validate sub-elements and be exactly what I need, however it seems it was deprecated and removed with nothing to replace it.

I then attempted to write custom validation to cycle through the list objects checking each one for being empty but the form just still submitted.

Fluent validation is another option but it wouldn't work and led to an error saying No pending ValidationResult found. I'm not sure if I perhaps need a parent class that has a subset of the list of classes but then only the main subclass is in the database and is the only one I want to insert into using the form.

Single Model (Validates As Expected)

I have created an EditForm in Blazor where I was able to easily add validation for a single model where I added OnValidSubmit to the form with the DataAnnotationsValidator and ValidationSummary tags at the top:

<EditForm FormName="CriminalConvictions" Model="criminalConvictions" OnValidSubmit="SubmitMany">
    <DataAnnotationsValidator />
    <ValidationSummary />

This is the model declaration where is instantiates a new instance of the model:

[SupplyParameterFromForm]
public CriminalConvictionModel? criminalConviction { get; set; }

protected override async Task OnInitializedAsync()
{
    criminalConviction ??= new();
}

Then I can add in the validation message under the field as well:

<InputTextArea @bind-Value="criminalConviction!.Offence" class="form-control" />
<ValidationMessage For="@(() => criminalConviction!.Offence)" />

And in the model class I can then add a required tag to require a value for this field:

public class CriminalConvictionModel
{
    public int CriminalConvictionID { get; set; }
    public DateTime? DateOfOffence { get; set; }

    [Required(ErrorMessage = "Please record details of the offence")]
    public string? Offence { get; set; }
    
    ...
}

This all works and validates the field as expected:

List of Model (Won't Validate)

However I now need to allow multiple items to be submitted so changed the model declaration to be a list of model objects like this:

public CriminalConvictionModel? criminalConviction { get; set; }
[SupplyParameterFromForm]
public List<CriminalConvictionModel>? criminalConvictions { get; set; }

protected override async Task OnInitializedAsync()
{
    criminalConviction ??= new();
    criminalConvictions = new List<CriminalConvictionModel>();
    criminalConvictions?.Add(criminalConviction);
}

Then I changed the submit function to save a list of models to the database which works and saves the records to the SQL database but the validation no longer works as this required field can now be left blank and it is not picked up and OnValidSubmit is being executed regardless of if the models in the list are valid or not.

If the EditForm model is set as the single criminalConviction then it validates the first set of elements but not subsequent ones but if I set it as the list I declared which is criminalConvictions then no validation occur and I can't work out what I need to change to make it work.

This is the function I added to add new models to the list of models to add a new set of form fields:

private void AddMoreConvictions() {
    formSubmitted = false;

    CriminalConvictionModel newConviction = new CriminalConvictionModel();
    criminalConvictions = new List<CriminalConvictionModel>();

    criminalConvictions?.Add(newConviction);
}

So it all works and saves multiple records to the database but I just can't work out how to get validation working for List<Model> when it works as expected for Model and I can't work out what I am missing and also ideally it would be better if the validation summary could be per list of fields so it is clear which set has the missing field.

Other Approaches Attempted

The most obvious approach to this from looking online is to use ObjectGraphDataAnnotationsValidator, which seems to validate sub-elements and be exactly what I need, however it seems it was deprecated and removed with nothing to replace it.

I then attempted to write custom validation to cycle through the list objects checking each one for being empty but the form just still submitted.

Fluent validation is another option but it wouldn't work and led to an error saying No pending ValidationResult found. I'm not sure if I perhaps need a parent class that has a subset of the list of classes but then only the main subclass is in the database and is the only one I want to insert into using the form.

Share Improve this question edited Dec 2, 2024 at 6:48 Zhi Lv 22k1 gold badge27 silver badges37 bronze badges asked Nov 28, 2024 at 10:00 Robin WilsonRobin Wilson 3883 silver badges12 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

After spending hours on this I have finally managed to solve it using the Blazored.FluentValidation package. I couldn't find any examples online that validate a list of elements or the ones I did find didn't work or used now deprecated or removed features but here is what did work in the end.

First install the Fluent Validation package in Package Manager:

Install-Package Blazored.FluentValidation

Now go to the _Imports.razor file and add an include for fluent validation to save adding it to every page:

@using Blazored.FluentValidation

In terms of models I just had the one called CriminalConvictionModel and declared a list of them in the page to be able to add multiple records and loop through these.

However this wouldn't work for validation as I needed to create a parent model which would just be a container for the list of items so as well as CriminalConvictionModel I had to create CriminalConvictionsModel as a new parent class:

public class CriminalConvictionsModel
{
    public ICollection<CriminalConvictionModel>? Convictions { get; set; }
}

I then had to make sure the model for the form was this parent class and the foreach loop to cycle through these became:

foreach (var conv in criminalConvictions.Convictions) {

}

Then I needed to add the validator code for a single record:

public class CriminalConvictionValidator : AbstractValidator<CriminalConvictionModel>
{
    public CriminalConvictionValidator()
    {
        RuleFor(c => c.Offence).NotEmpty();
    }
}

Then I needed to add a validator for the parent class with a ForEach command that would then call the singular validator for each record:

public class CriminalConvictionsValidator : AbstractValidator<CriminalConvictionsModel>
{
    public CriminalConvictionsValidator()
    {
        RuleFor(c => c.Convictions).ForEach(x => x.SetValidator(new CriminalConvictionValidator()));
    }
}

Finally I needed to change DataAnnotationsValidator /> at the top of the form to <FluentValidationValidator @ref="_fluentValidationValidator" /> and change OnValidSubmit to OnSubmit then add this in the @code area:

private FluentValidationValidator? _fluentValidationValidator;

Then change the submit function so all the code is contained in this if statement:

if (await _fluentValidationValidator!.ValidateAsync())
{
   //Submit form
}

Now each set of fields are validated as needed:
[![It Works][1]][1]

And I changed the submit code to submit `criminalConvictions.Convictions` so it is in effect submitting the same format of data to the API and again successfully saving to the database.

Hopefully this helps others as working this out without any examples has taken ages and lots of trial and error but at least I'll know for next time and it saves reverting to JS.

  [1]: https://i.sstatic/bm6Xg4OU.png

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745517789a4631103.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信