dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.34k stars 9.99k forks source link

Blazor Validations: Need dynamic form validations without Data Annotations #9604

Closed VR-Architect closed 5 years ago

VR-Architect commented 5 years ago

Is your feature request related to a problem? Please describe.

When building a blazor form dynamically, it is not possible to know the data model. Thus it would not be possible to put validation data annotations on the model.

Describe the solution you'd like

We need the ability to dynamically create a data validation model. We could pass in a list of controls with Id, FeedbackValid (nullable), FeedbackInvalid, etc. Then the validation process would run through the list doing the validations and set the class invalid and show the Feedback accordingly.

Describe alternatives you've considered

Falling back to the basic BootStrap form validation for client side and validation in the controller on server-side. Server returns a list of control Id's with errors and client marks the classes invalid

Additional context

In my opinion this is a cleaner method as we can use all BootStrap controls with native BootStrap look & feel

danroth27 commented 5 years ago

Hi @VR-Architect. I believe all the pieces you need to implement this are available in Blazor. You can dynamically generate the form and then use your own validation logic in place of the data annotations support that we include in the box.

SteveSandersonMS commented 5 years ago

That's right.

It sounds like you want a custom alternative to <DataAnnotationsValidator />. To see how to do that, check the sources for that component. It's fairly simple:

VR-Architect commented 5 years ago

FYI, I found a way to accomplish this which you may want to add to a knowledge-base?

My save/update api calls return a list of control ID's which failed server-side validation and on the client iterate through the list and call a JavaScript function to set the control's class to is-invalid. Here is my code for others looking for a similar solution.

Index.html file

        window.ShowValidation = {
            elementId: function (Id, mode) {
                var element = document.getElementById(Id);
                if (element != null) {
                    switch (mode) {
                        case 'is-valid':
                            element.classList.remove('is-invalid');
                            element.classList.add('is-valid');
                            break;
                        case 'is-invalid':
                            element.classList.remove('is-valid');
                            element.classList.add('is-invalid');
                            break;
                        default:
                            element.classList.remove('is-valid');
                            element.classList.remove('is-invalid');
                    }
                }
            }
        }

In your .razor file's save function:

response = await Http.PostJsonAsync<MyResponse>("api/MyData/", MyData);

if (!response.Success)
{
    foreach (var f in response.FieldsFailingValidation)
    {
        await jsRuntime.InvokeAsync<object>("ShowValidation.elementId", f.Id.ToString(), "is-invalid");
    }
}       

In shared project:

using System;
using System.Collections.Generic;
using System.Text;

namespace VC1.Shared
{
    public class MyResponse
    {
        public bool Success { get; set; } = true;
        public string Message { get; set; }
        public List<MyField> FieldsFailingValidation{ get; set; } 
    }

    public class MyField
    {
        public Int32 Id { get; set; }
        public string ErrorMsg { get; set; }
    }
}