首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Blazor Modal表单验证:删除表单字段时,必须单击“取消”按钮两次才能关闭该模式

Blazor Modal表单验证:删除表单字段时,必须单击“取消”按钮两次才能关闭该模式
EN

Stack Overflow用户
提问于 2020-01-17 12:07:04
回答 4查看 14K关注 0票数 8

在Blazor中,我使用模态对话框作为CRUD。当我打开一个模式来编辑一个记录,并删除(例如)用户名,然后直接单击Cancel按钮,表单验证仍然会启动。模态不关闭。

我需要再次点击取消按钮关闭模式。

我知道我可以将cancel按钮放在EditForm之外,但是在对话框关闭之前,您将看到一条验证消息在闪烁。我希望我的取消按钮在我的提交按钮在模态页脚旁边。

当我按下“取消”按钮时,是否有任何方法来覆盖表单验证?我不想使用JavaScript互操作,只是普通的Blazor。

“工作守则”示例:

代码语言:javascript
复制
@page "/cancel"
@using System.ComponentModel.DataAnnotations;

<h3>Cancel Validation</h3>

<button type="submit" class="btn btn-primary" @onclick="Login">Login</button>
<hr />
<p>Status: @status</p>

@if (showModal)
{
    <div class="modal" tabindex="-1" role="dialog" style="display:block" id="taskModal">
        <div class="modal-dialog shadow-lg bg-white rounded" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Login</h5>
                </div>
                <div class="modal-body">
                    <EditForm Model="user" OnValidSubmit="HandleValidSubmit">
                        <DataAnnotationsValidator />
                        <ValidationSummary />
                        <div class="form-group row">
                            <label class="col-3 col-form-label">Email: </label>
                            <InputText class="col-8 form-control" @bind-Value="user.Email" />
                        </div>
                        <div class="form-group row">
                            <label class="col-3 col-form-label">Password: </label>
                            <InputText type="password" class="col-8 form-control" @bind-Value="user.Password" />
                        </div>
                        <div class="modal-footer">
                            <button type="submit" class="btn btn-primary">Submit</button>
                            <button type="button" class="btn btn-secondary" @onclick="CancelSubmit">Cancel</button>
                        </div>
                    </EditForm>
                </div>
            </div>
        </div>
    </div>
}

@code {

    public class UserLogin
    {
        [Required(ErrorMessage = "Email is required")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Password is required")]
        public string Password { get; set; }
    }

    UserLogin user = new UserLogin();

    bool showModal;
    string status;

    protected override void OnInitialized()
    {
        showModal = false;
        status = "Init";
        // for demo purposes, if you delete user.Email in the login dialog, you'll need to press 'Cancel' 2 times.
        user.Email = "user@example.com";
        user.Password = "12345";
    }

    private void Login()
    {
        status = "Show Login Modal";
        showModal = true;
    }

    private void HandleValidSubmit()
    {
        status = "Valid Submit";
        showModal = false;
    }

    private void CancelSubmit()
    {
        status = "Cancelled"; 
        showModal = false;
    }
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2021-05-28 10:38:49

今天我找到了一个更简单的解决方案..。只需使用a而不是:)

因此,只需将“取消”按钮更改为:

代码语言:javascript
复制
   <div type="button" class="btn btn-secondary" @onclick="CancelSubmit">Cancel</div>

验证不会以这种方式触发,但您的服务器端代码仍将被正常执行。

票数 4
EN

Stack Overflow用户

发布于 2020-01-18 20:03:14

@Jaap,这是一个基于表单验证内部的解决方案。我希望它能让你满意,直到找到更好的解决方案。

在EditContext对象中添加的表单验证支持在两个级别上执行:对象级和字段级。单击Submit按钮时,将验证整个模型。我们已经看到Submit按钮工作得非常好,并且不允许您提交,除非模型的字段的值是有效的。当您点击Cancel按钮,并且Model字段的值是有效的时,对话框就会被关闭,而不会出现问题。但是,当一个或多个字段的值无效(例如,在清除电子邮件字段之后),然后单击Cancel按钮,字段级别的验证就会立即启动,然后取消按钮的事件处理程序中的代码才有机会做一些事情。这种行为是通过设计进行的,甚至在我使用Fluent验证而不是DataAnnotations验证时也会重复。结论:这是我们的局限,而不是制度。我们需要投入更多的时间来学习Blazor。我建议的解决方案是在单击Cancel按钮时禁用字段级验证,从而立即关闭对话框,而不需要进行任何验证。

注意:我的代码使用的是Fluent验证,就像我尝试使用Fluent验证一样,但是DataAnnotations验证也可以这样做。这两种情况下的代码几乎是相同的,实际上与流畅的验证无关。请注意,我已经通过克里斯·桑蒂修改了Fluent验证示例代码。

UserLogin.cs

代码语言:javascript
复制
public class UserLogin
{
    public string Email { get; set; }
    public string Password { get; set; }
}

UserLoginValidator.cs

代码语言:javascript
复制
public class UserLoginValidator : AbstractValidator<UserLogin>
    {
       public UserLoginValidator()
     {

         RuleFor(user => user.Email).NotEmpty().WithMessage("You must enter an email address");
         RuleFor(user => user.Email).EmailAddress().WithMessage("You must provide a valid email address");
         RuleFor(user => user.Password).NotEmpty().WithMessage("You must enter a password");
         RuleFor(user => user.Password).MaximumLength(50).WithMessage("Password cannot be longer than 50 characters");
    }
 }

FluentValidationValidator.cs

代码语言:javascript
复制
public class FluentValidationValidator : ComponentBase
{
    [CascadingParameter] EditContext CurrentEditContext { get; set; }
    [Parameter] public bool ShouldValidate { get; set; }

    protected override void OnInitialized()
    {
        if (CurrentEditContext == null)
        {
            throw new InvalidOperationException($"{nameof(FluentValidationValidator)} requires a cascading " +
                $"parameter of type {nameof(EditContext)}. For example, you can use {nameof(FluentValidationValidator)} " +
                $"inside an {nameof(EditForm)}.");
        }

        CurrentEditContext.AddFluentValidation(ShouldValidate);
    }
}

EditContextFluentValidationExtensions.cs

代码语言:javascript
复制
 public static class EditContextFluentValidationExtensions
{
    public static EditContext AddFluentValidation(this EditContext editContext, bool shouldValidate)
    {
        if (editContext == null)
        {
            throw new ArgumentNullException(nameof(editContext));
        }

        var messages = new ValidationMessageStore(editContext);

        editContext.OnValidationRequested +=
            (sender, eventArgs) => ValidateModel((EditContext)sender, messages);

        editContext.OnFieldChanged +=
            (sender, eventArgs) => ValidateField(editContext, messages, eventArgs.FieldIdentifier, shouldValidate);

        return editContext;
    }

    private static void ValidateModel(EditContext editContext, ValidationMessageStore messages)
    {
        var validator = GetValidatorForModel(editContext.Model);
        var validationResults = validator.Validate(editContext.Model);

        messages.Clear();
        foreach (var validationResult in validationResults.Errors)
        {
            messages.Add(editContext.Field(validationResult.PropertyName), validationResult.ErrorMessage);
        }

        editContext.NotifyValidationStateChanged();
    }

    private static void ValidateField(EditContext editContext, ValidationMessageStore messages, in FieldIdentifier fieldIdentifier, bool shouldValidate)
    {
        Console.WriteLine(fieldIdentifier.FieldName.ToString());

        if (shouldValidate)
        {
            var properties = new[] { fieldIdentifier.FieldName };
            var context = new FluentValidation.ValidationContext(fieldIdentifier.Model, new PropertyChain(), new MemberNameValidatorSelector(properties));

            var validator = GetValidatorForModel(fieldIdentifier.Model);
            var validationResults = validator.Validate(context);

            messages.Clear(fieldIdentifier);

            foreach (var validationResult in validationResults.Errors)
            {
                messages.Add(editContext.Field(validationResult.PropertyName), validationResult.ErrorMessage);
            }

            editContext.NotifyValidationStateChanged();
        }
    }

    private static IValidator GetValidatorForModel(object model)
    {
        var abstractValidatorType = typeof(AbstractValidator<>).MakeGenericType(model.GetType());
        var modelValidatorType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.IsSubclassOf(abstractValidatorType));
        var modelValidatorInstance = (IValidator)Activator.CreateInstance(modelValidatorType);

        return modelValidatorInstance;
    }
}

Cancel.razor

代码语言:javascript
复制
@page "/cancel"
@using System.ComponentModel.DataAnnotations;

<h3>Cancel Validation</h3>

<button type="submit" class="btn btn-primary" @onclick="Login">Login</button>
<hr />
<p>Status: @status</p>

@if (showModal)
{
    <div class="modal" tabindex="-1" role="dialog" style="display:block" id="taskModal">
        <div class="modal-dialog shadow-lg bg-white rounded" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Login</h5>
                </div>
                <div class="modal-body">
                    <EditForm Model="user" OnValidSubmit="HandleValidSubmit">
                        @*<DataAnnotationsValidator />*@
                        <FluentValidationValidator ShouldValidate="false" />
                        @*<ValidationSummary />*@
                        <div class="form-group row">
                            <label class="col-3 col-form-label">Email: </label>
                            <InputText class="col-8 form-control" @bind-Value="user.Email" />
                            <ValidationMessage For="@(() => user.Email)" />
                        </div>
                        <div class="form-group row">
                            <label class="col-3 col-form-label">Password: </label>
                            <InputText type="password" class="col-8 form-control" @bind-Value="user.Password" />
                            <ValidationMessage For="@(() => user.Password)" />
                        </div>
                        <div class="modal-footer">
                            <button type="submit" class="btn btn-primary">Submit</button>
                            <button type="button" class="btn btn-secondary" @onclick="CancelSubmit">Cancel</button>
                        </div>
                    </EditForm>
                </div>
            </div>
        </div>
    </div>
}

@code {
    UserLogin user = new UserLogin();

    bool showModal;
    string status;

    protected override void OnInitialized()
    {
        showModal = false;
        status = "Init";
        // for demo purposes, if you delete user.Email in the login dialog, you'll need to press 'Cancel' 2 times.
        user.Email = "user@example.com";
        user.Password = "12345";
    }

    private void Login()
    {
        status = "Show Login Modal";

        showModal = true;
    }

    private void HandleValidSubmit()
    {
        status = "Valid Submit";
        showModal = false;
    }

    private void CancelSubmit()
    {
        Console.WriteLine("CancelSubmit");

        status = "Cancelled";
        showModal = false;
    }
}

注意,FluentValidationValidator组件有一个名为ShouldValidate的属性,为了删除字段级验证,我们将其设置为false。拜托,跟着执行的流程--这很简单。我几乎没有做任何事情来解决这个问题,这让我认为也许有一个更短和更好的方法来解决这个问题。您可能需要安装Fluent验证包..。祝你好运。

票数 4
EN

Stack Overflow用户

发布于 2020-01-18 14:28:36

所以我在这里发现了一些新的东西:ASP.NET核心Blazor表单及其验证

默认情况下,<ValidationSummary style="@displaySummary" />是禁用的,当有InvalidSubmit时,我会启用它。

这不是一个理想的解决方案,因为当用户(1)删除字段的内容时,(2)单击“Submit”,验证就会启动,但是如果用户在同一字段中输入有效的内容,(3)用户必须单击“Submit”两次。但就目前而言,我可以接受这种情况,因为这种情况并不经常发生。

新的工作守则:

代码语言:javascript
复制
@page "/cancel"
@using System.ComponentModel.DataAnnotations;

<h3>Cancel Validation</h3>

<button type="submit" class="btn btn-primary" @onclick="OpenDialog">Open Dialog</button>
<hr />
<div>@((MarkupString)status)</div>

@if (showModal)
{
    <div class="modal" tabindex="-1" role="dialog" style="display:block" id="taskModal">
        <div class="modal-dialog shadow-lg bg-white rounded" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Cancel Test</h5>
                    <button type="button" class="close" @onclick="CancelSubmit"><span aria-hidden="true">&times;</span></button>
                </div>
                <div class="modal-body">
                    <div>
                        <EditForm Model="@user" OnValidSubmit="HandleValidSubmit" OnInvalidSubmit="HandleInValidSubmit">
                            <DataAnnotationsValidator />
                            <ValidationSummary style="@displaySummary" />
                            <div class="form-group row">
                                <label class="col-3 col-form-label">Email</label>
                                <InputText class="col-8 form-control" @bind-Value="user.Email" />
                            </div>
                            <div class="form-group row">
                                <label class="col-3 col-form-label">Password</label>
                                <InputText type="password" class="col-8 form-control" @bind-Value="user.Password" />
                            </div>
                            <div class="modal-footer">
                                <button type="submit" class="btn btn-primary">Submit</button>
                                <button type="button" class="btn btn-secondary" @onclick="CancelSubmit">Cancel</button>
                            </div>
                        </EditForm>
                    </div>
                </div>
            </div>
        </div>
    </div>
}

@code {

    public class UserLogin
    {
        [Required(ErrorMessage = "Email is required")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Password is required")]
        public string Password { get; set; }
    }

    private UserLogin user = new UserLogin();

    bool showModal = false;
    private string displaySummary = "display:none";
    string status = "";

    protected override void OnInitialized()
    {
        InitUser();
    }

    private void InitUser()
    {
        // for demo purposes, think of it as an 'edit dialog' in CRUD operation.
        status += "Init User";
        user.Email = "user@example.com";
        user.Password = "12345";
        displaySummary = "display:none";
    }

    private void OpenDialog()
    {
        status += "<br />Open User Dialog";
        showModal = true;
    }

    private void HandleValidSubmit()
    {
        status += "<br />Valid Submit";
        displaySummary = "display:none";
        showModal = false;
    }

    private void HandleInValidSubmit()
    {
        displaySummary = "display:block";
        status += "<br />Invalid Submit";
    }

    private void CancelSubmit()
    {
        status += "<br />Cancelled<br /><br />";
        InitUser(); // for demo purposes so you can test it multiple times
        showModal = false;
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59787064

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档