简体   繁体   中英

Blazor Validation | How to clear a custom error message

I'm new to Blazor and working on an EditFrom.

I have regular validation with FluentValidation and then I need to run a custom validation to make sure the email is not a duplicate.

That code is working good except, when I go to fix the email address and change it back to an email that I know is valid, the custom error message does not clear out on the validationSummary or the email field.

It appears the call for OnSubmit is not being fired even though all of the other validations are clear except the custom one.

What am I doing wrong?

I've tried everything from this post: How to create Custom Data Annotation Validators

Code:

Razor:

@page "/Identity/Account/ManageProfile"

@using Microsoft.AspNetCore.Identity
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.Inputs
@using Syncfusion.Blazor.Notifications
@inject UserManager<ApplicationUser> userManager
@inject AuthenticationStateProvider authenticationStateProvider
@inject UserUtilities UserUtilities;
@attribute [Authorize]

<style>
    .control-container {
        width: 400px;
    }

    .btn-update {
        margin-top: 20px;
    }

    .e-btn{
        width: 100%;
        font-size: 20px;
    }
</style>


<EditForm Model="@Input" OnValidSubmit="@UpdateProfile">
    <FluentValidator TValidator="InputModelValidator" />
    <div class="form-row">
        <div class="form-group col-md-6">
            <h2>Manage Profile</h2>
        </div>
    </div>
    <ValidationSummary />
    <div class="form-row">
        <div class="form-group col-md-4">
            <SfTextBox FloatLabelType="FloatLabelType.Auto" Placeholder="First Name" @bind-Value="Input.FirstName"></SfTextBox>
        </div>
        <div class="form-group col-md-4">
            <SfTextBox FloatLabelType="FloatLabelType.Auto" Placeholder="Last Name" @bind-Value="Input.LastName"></SfTextBox>
        </div>
    </div>
    <div class="form-row">
        <div class="form-group col-md-4">
            <SfTextBox FloatLabelType="FloatLabelType.Auto" Placeholder="Email Address" @bind-Value="Input.Email"></SfTextBox>
        </div>
    </div>
    <div class="form-row btn-update">
        <div class="form-group col-md-4">
            <SfButton IsPrimary="true">Update</SfButton>
            <SfToast ID="toast_customDupemail" @ref="@toastDuplicateEmail" Title="Invalid Email" Content="@toastDupEmailErrorMsg" CssClass="e-toast-danger" Timeout=6000>
                <ToastPosition X="Center" Y="Top"></ToastPosition>
             </SfToast>
        </div>
    </div>
</EditForm>

CodeBehind:

using Microsoft.AspNetCore.Components.Forms;
using System.ComponentModel.DataAnnotations;
using FluentValidation;
using Syncfusion.Blazor.Notifications;

namespace UI.Areas.Identity.Pages.Account
{
    public partial class ManageProfile
    {
        public InputModel Input { get; set; } = new InputModel();
        private string toastDupEmailErrorMsg = string.Empty;
        private SfToast toastDuplicateEmail;

        protected override async Task OnInitializedAsync() // = On Page Load
        {
            var userInfo = await UserUtilities.GetApplicationUser().ConfigureAwait(false);

            Input = new InputModel
            {
                FirstName = userInfo.FirstName,
                LastName = userInfo.LastName,
                Email = userInfo.Email
            };

            EditContext _editContext = new EditContext(Input);
            var _msgStore = new ValidationMessageStore(_editContext);
            //_editContext.OnValidationRequested += (s, e) => _msgStore.Clear();
            _editContext.OnFieldChanged += (s, e) => _msgStore.Clear(e.FieldIdentifier);
        }

        private async Task UpdateProfile(EditContext context)
        {
            //if (_editContext.Validate()) // <-- Model Validation
            //{
            //    if (await IsEmailValid(Input.Email).ConfigureAwait(false) == false)
            //    {
            //        await InvokeAsync(async () =>
            //        {
            //            var messages = new ValidationMessageStore(_editContext);
            //            messages.Clear();
            //            messages.Add(() => Input.Email, $"Username '{Input.Email}' is already taken.");
            //            _editContext.NotifyValidationStateChanged();
            //            StateHasChanged();
            //        }).ConfigureAwait(false);
            //    }
            //}

            if (await IsEmailValid(Input.Email).ConfigureAwait(false) == false)
            {
                await InvokeAsync(async () =>
                {
                    var messages = new ValidationMessageStore(context);
                    messages.Clear();
                    messages.Add(() => Input.Email, $"Username '{Input.Email}' is already taken.");
                    context.EnableDataAnnotationsValidation();
                    context.NotifyValidationStateChanged();
                    StateHasChanged();
                }).ConfigureAwait(false);
            }
        }

        private async Task<bool> IsEmailValid(string email)
        {
            var userInfo = await UserUtilities.GetApplicationUser().ConfigureAwait(false);

            if (string.Equals(userInfo.Email, email, StringComparison.OrdinalIgnoreCase) == true)
            {
                return true;
            }

            var user = await userManager.FindByEmailAsync(Input.Email).ConfigureAwait(false);

            if (user != null)
            {
                return false;
            }

            return true;
        }
    }

    public class InputModel
    {
        [Required]
        [MaxLength(250)]
        [Display(Name = "First Name", Prompt = "Enter first name")]
        public string FirstName { get; set; }

        [Required]
        [MaxLength(250)]
        [Display(Name = "Last Name", Prompt = "Enter last name")]
        public string LastName { get; set; }

        /// <summary>
        ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        [Required]
        [EmailAddress]
        [Display(Name = "Email", Prompt = "Enter email")]
        public string Email { get; set; }
    }

    public class InputModelValidator : AbstractValidator<InputModel>
    {
        public InputModelValidator()
        {         
            RuleFor(e => e.FirstName).NotEmpty().WithMessage("First name is required.");
            RuleFor(e => e.LastName).NotEmpty().WithMessage("Last name is required.");
            RuleFor(e => e.Email).NotEmpty().WithMessage("Email is required.");
            RuleFor(e => e.Email).EmailAddress().WithMessage("Email is not valid.");
        }
    }
}

Update 2:

I've tried pretty much all of these suggestions: How to reset custom validation errors when using editform in blazor razor page

I was able to fix it with this example . I created the customFormValidator and then put that within my EditForm

<EditForm Model="@Input" OnValidSubmit="@UpdateProfile">
    <FluentValidator TValidator="InputModelValidator" />
    <UI.Models.Other.CustomFormValidator @ref="@customFormValidator" />

Then in UpdateProfile I was able to clear it out.

Also, once I cleared out the email address that was now valid, the error cleared.

I assume that I was interacting the custom validation within FluentValidation and I needed a stand alone validator.

        private async Task UpdateProfile(EditContext context)
        {
            customFormValidator.ClearFormErrors();

            if (await IsEmailValid(Input.Email).ConfigureAwait(false) == false)
                var errors = new Dictionary<string, List<string>>();

                errors.Add("Email", new List<string>
                {
                    $"Username '{Input.Email}' is already taken."
                });

                await InvokeAsync(async () =>
                {
                    customFormValidator.DisplayFormErrors(errors);
                    StateHasChanged();
                }).ConfigureAwait(false);
            }
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM