【问题标题】:Blazor - How to make child component show validation messages?Blazor - 如何让子组件显示验证消息?
【发布时间】:2021-02-11 10:22:07
【问题描述】:

如果嵌套组件未正确填写,我需要显示验证消息。该组件被其他父组件使用,他们需要获得有关是否存在验证问题的反馈。

我已经为嵌套组件尝试了以下代码并使用了CanSubmit 方法。虽然该方法可以正确判断是否存在验证问题,但验证消息并未显示。

以下所有代码都可以在 blzorrepl 上进行测试: https://blazorrepl.com/repl/GvOQlvvv1789ra1G37

@if(editContext != null) {
    <EditForm EditContext="@editContext">
        <input type="text" @bind="testModel.Name" />
        <DataAnnotationsValidator />
        <ValidationSummary />
    </EditForm>
}

@code {
    [Parameter]
    public TestModel testModel
    {
        get { return (TestModel)editContext?.Model; }
        set { editContext = new EditContext(value); }
    }

    EditContext editContext;

    public bool CanSubmit()
    {
        return editContext.Validate();
    }
}

这是我的父组件代码,有点减少但重现了问题:

<ChildComponent @ref="myTestComponent" testModel="testModel" />
<input type="button" @onclick="buttonClick" value="validate programmatically" />
<div>@testMessage</div>

@code {
    TestModel testModel = new TestModel();
    ChildComponent myTestComponent;
    string testMessage;

    void buttonClick()
    {
        testMessage = "not passed validation";

        if (myTestComponent.CanSubmit())
        {
            testMessage = "passed validation!";
        }
    }
}

testMessage 仅用于显示验证状态。

如何使父组件导致嵌套组件显示验证消息?我只能将submit 放在父组件中。

根据要求,这里有一个更完整的示例来说明我正在做的事情,一个可以编辑的项目列表内联,以及一个用于添加更多实例的表单。 https://blazorrepl.com/repl/mlYwlQPm34bekYE824

【问题讨论】:

  • 您将需要一个自定义验证器。 EditForm 仅适用于 InputCheckBox、InputDate 等内置表单组件。您可以查看 Micorsoft 文档
  • @JoeGER94 如果我在submit 中输入并单击submit,我可以显示验证消息。我不明白为什么我应该使用内置组件——它们如何让验证消息在这种情况下开始显示?
  • 您使用&lt;input&gt; 而不是&lt;InputText&gt; 有什么原因吗?从InputBase 继承的组件具有许多内置功能,例如验证。如果您将其更改为&lt;InputText @bind-Value="testModel.Name" /&gt;,它应该可以工作。请记住,必须在 ValidationSummary 显示某些内容之前修改该字段。因此,添加文本、删除文本、关注其他内容应该会触发验证。
  • @Justthebenno 我希望在运行CanSubmit 方法时显示错误消息。将input 更新为InputText 在模糊事件中显示验证消息,但是当我按下提交按钮时,该消息再次被隐藏。
  • 我想知道您为什么决定使用这种方法?您不知道InputText 组件还是您选择的根本原因?这将导致下一个问题:一旦设置了testModel 的参数,您为什么决定创建EditContext?如果单击父组件中的按钮,它将触发渲染周期。在此循环期间,将(再次)设置参数。所以每次,EditContext 及其验证状态都会被重置。

标签: blazor blazor-component


【解决方案1】:

我将尝试解释为什么您的方法不起作用,然后提出解决方法。希望我能正确理解您的意图。

首先您需要将&lt;input type="text" ...&gt; 更改为&lt;InputText @bind-Value="..." /&gt;

当您的方法 buttonClick 在您的父组件中完成时,Blazor 将在您的组件上调用 StateHasChanged。它是EventHandler 的内置逻辑的一部分。这将触发您的子组件的组件生命周期。在该周期内,您的子组件属性 testModel 的设置器将再次被调用。 Blazor 不会对相等性进行任何测试。 (唯一强大的检查引擎是渲染周期结束时的DiffierentialRenderTree)。这意味着将创建一个新的EditContext。但是,此上下文不知道验证错误。因此消息消失。为了证明这一点,请在 setter 中设置一个计数器变量并将其显示在页面上。你会看到这个结果。

.

为避免这种情况,您可以在设置参数时创建一次EditContext

@code {

    [Parameter]
    public TestModel testModel { get; set; }

    EditContext editContext;

   protected override void OnParametersSet()
   {
       base.OnParametersSet();
       if(editContext == null)
       {
           editContext = new EditContext(testModel);
       }
   }

    public bool CanSubmit()
    {
        return editContext.Validate();
    }
}

如果您需要更新模型但保留验证状态,请写评论,我们可以从那里开始。

【讨论】:

  • 谢谢,非常有用。我更新了ChildComponentsetter 以仅在给定TestModel 的新实例时设置EditContext。尽管保留了&lt;input type="text"&gt;,但它正是我现在需要的。这是更新的 repl blazorrepl.com/repl/QFuGvmkX53o67uV758 这是最好的解决方案吗?或者你有什么建议?
  • 我认为您有一个非常特殊的问题并选择了一个独特的解决方案。因为我没有看到或理解您的上下文,所以我不能提出“更好”的方法。 @JoeGER94 具有级联参数的解决方案也可能是一个很好的解决方案。此外,我认为写它会增加误解的程度:)。我可以为您提供的是一个电话/聊天,您可以在其中向我展示上下文,希望在那之后,我可以回答您的问题。
  • @jakubiszon 我个人认为这个解决方案很难阅读,并且做了很多如果你使用我的方法就不需要的事情。此外,如果您按照问题中的描述在不同的父母中使用它可能会出现问题。对 Cascading-Value 的更改将在每个消费 Child 和反向中更新。
  • 我在问题的底部添加了另一个 repl 链接。基本上我需要在页面上两次引用同一个编辑器,并且每种情况下的按钮集都是不同的。
【解决方案2】:

我有不同的方法.. 你的父母必须是这样的

<CascadingValue Value="testModel">
    <EditForm Model="testModel">
        <ChildComponent @ref="myTestComponent" />
        <ObjectGraphDataAnnotationsValidator />
        <ValidationMessage For="@(()=>testModel.Name)" />
        <br />
        <button type="submit">test</button>
    </EditForm>
</CascadingValue>

您现在对孩子唯一需要做的就是这样

@if (testModel != null)
{
  <InputText @bind-Value="testModel.Name" />
}

@code {

    [CascadingParameter]
    public TestModel testModel { get; set; }
}

我个人认为代码少...

【讨论】:

  • 非常有趣。这是我使用您的方法blazorrepl.com/repl/wFkmbclL55yO5QFn38 的工作 REPL 它通过提交单个 EditForm 来工作。我认为这有点不灵活。我在回答中使用的方法将允许在一个事件中使用两个单独的子组件(例如联系方式 + 送货地址)。我需要做的就是在每个子控件上实现和调用验证方法(在本例中名为 CanSubmit),以了解我是否可以处理这两个模型。否则我需要编写另一个模型或使用更多提交按钮,对吗?
  • @jakubiszon 好吧......我的主要方法会比你的更通用。首先,我不会“硬编码”Childs。我会动态渲染它们,使其更具可扩展性,并且我会在 Childs 中使用一些多态代码来防止一直编写相同的代码。我们都使用不同的方式 - 两者都是可能的......
  • @JoeGET94 听起来确实很有趣。你知道我可以在网上找到这种方法的任何例子吗?
  • @jakubiszon 您可以使用 RenderTreeBuilder 动态渲染 Razor 组件。首先检查这个blazor-university.com/…,然后像史蒂夫桑德森在这里解释的那样生成它:github.com/dotnet/aspnetcore/issues/…
【解决方案3】:

最初的问题是分配EditContext。必须访问它,但可以通过editForm.EditContext 完成,如下例所示。

工作示例https://blazorrepl.com/repl/Glkmbcbr323MP1VS55

父组件:

<ChildComponent @ref="myTestComponent" testModel="testModel" />
<input type="button" @onclick="buttonClick" value="validate programmatically" />
<div>@testMessage</div>

@code {
    TestModel testModel = new TestModel();
    ChildComponent myTestComponent;
    string testMessage;

    void buttonClick()
    {
        testMessage = "not passed validation";

        if (myTestComponent.CanSubmit())
        {
            testMessage = "passed validation!";
        }
    }
}

子组件:

@if(testModel != null) {
    <EditForm @ref="editForm" Model="@testModel">
        <input type="text" @bind="testModel.Name" />
        <DataAnnotationsValidator />
        <ValidationSummary />
    </EditForm>
}

@code {
    [Parameter]
    public TestModel testModel
    {
        get; set;
    }

    EditForm editForm;

    public bool CanSubmit()
    {
        return editForm.EditContext.Validate();
    }
}

【讨论】:

    猜你喜欢
    • 2021-06-10
    • 2021-08-07
    • 2023-03-08
    • 1970-01-01
    • 2021-09-11
    • 2016-10-31
    • 1970-01-01
    • 2014-06-04
    • 1970-01-01
    相关资源
    最近更新 更多