【问题标题】:EditForm validation not applying invalid class to custom componentEditForm 验证未将无效类应用于自定义组件
【发布时间】:2021-10-02 19:56:27
【问题描述】:

在使用 blazor 时,创建可重用的自定义组件很重要;这是使用 Blazor 的要点之一。

我已经创建了一个基本的 Input 组件,它使用 Bootstrap 作为它的 CSS,如图所示。

@inherits InputBase<string>

<InputText type="@Type"
           class="form-control"
           id="@_id"
           placeholder="@Placeholder"
           @bind-Value="CurrentValue"
           disabled="@Disabled"
           @attributes="AdditionalAttributes"/>
/* Additional properties below for placeholder, disabled, type, etc. they're just string properties */

我把它放在一个 EditForm 中...

<EditForm Model="MyModel"
      OnValidSubmit="ViewModel.CreateAsync">
    <DataAnnotationsValidator />

<PrimaryInput @bind-Value="MyModel.Name"
              Placeholder="Name..."/>

</EditForm>

问题是,这不会将“无效”类添加到项目中。有效和修改都会出现,但是一旦输入变为无效,它不会像使用非自定义组件那样将有效更改为无效。下面是我的模型,显示我已向模型添加了验证。

public class MyModel
{
    [StringLength(5)]
    [Required]
    public string Name { get; set; }
}

下面是显示的图片:

这是 Blazor 生成的 html...

<input type="text" id="aa106d17-46d7-442c-be39-6c947f17186b" placeholder="Name..." aria-describedby="14b1189e-c3c5-4e1f-ae1d-330756147b44" class="form-control valid" aria-invalid="">

...如您所见,该类仍然有效,但已应用 aria-invalid 属性。以下是正在验证的非自定义组件输入的 HTML...

<input class="modified invalid" aria-invalid="">

...在这个上,无效。某些东西阻止了自定义组件上的类切换为无效。

【问题讨论】:

    标签: c# html blazor blazor-webassembly


    【解决方案1】:

    您需要触发表单的EditContext。有几种方法可以做到这一点 - 我将概述其中的两种。

    在您的自定义组件中,您可以覆盖 TryParseValueFromString 并在那里处理验证 - InputBase&lt;&gt; 在其中包含这些属性。考虑到您的类型已经是 string,这可能没有意义。

    否则,您可以让您的自定义组件将EditContext 作为级联参数注入,然后在更改时使用事件回调来调用EditContextNotifiedFieldChanged

    下面这个第二个例子的小例子:

    [CascadingParameter]
    private EditContext EditContext { get; set; }
    
    [Parameter] 
    private Expression<Func<string>> ValueExpression { get; set; }
    
    private FieldIdentifier _field;
    
    private void OnInitialized()
    {
        _field = FieldIdentifier.Create(ValueExpression);
    } 
    
    private void OnInputChanged(ChangeEventArgs args)
    {
        EditContext.NotifyFieldChanged(_fieldIdentifier);
    }
    

    【讨论】:

    • 您介意更详细一点吗?不完全确定我在做什么,或者是否有一些文档描述了这一点?我正在尝试您的第二个示例,但不确定该怎么做。 &lt;input @bind-value="@Value" class="form-control" @onchange="OnInputChanged" /&gt; 这是我的代码,然后我也有您在答案中发布的代码示例,但我不确定它应该是什么样子。
    【解决方案2】:

    我在我的自定义组件中使用以下代码修复了它....

    @inherits InputText
    
    <InputText class="form-control"
     Value="@Value"
     ValueExpression="ValueExpression"
     ValueChanged="OnInputChanged" />
    

    ... 继承带有 InputText 的 InputText 有点奇怪。我的代码是这样的......

    private void OnInputChanged(string value)
    {
        CurrentValueAsString = value;
        EditContext.NotifyFieldChanged(FieldIdentifier);
    }
    

    然后在我的代码中我像这样放置该组件....

    <TestInput @bind-Value="ViewModel.Menu.Name"/>
    

    这是一个有点奇怪的工作,但是当它有效/无效时,它可以完成工作并应用正确的类。

    【讨论】:

      【解决方案3】:

      您从&lt;InputBase&gt; 继承并在其中放置InputTextInputBase 控件)。这真的没有意义。

      以下示例演示了如何自定义标准 InputText。它展示了如何添加自定义属性、处理disabled 的一种方法、如何将用户输入的属性添加到输入中,以及如何更新键盘输入的值而不是失去焦点。

      @namespace Blazor.Starter.Components
      @inherits InputText
      
          <input type="text" disabled="@Disabled" value="@this.CurrentValue" @oninput="OnInput" @ref="Element" id="@Id" @attributes="this.AdditionalAttributes" />
      
      @code{
      
         [Parameter] public ElementReference? Element { get; set; }
         [Parameter] public string? Id { get; set; }
         [Parameter] public bool Disabled { get; set; }
      
          private void OnInput(ChangeEventArgs e)
              => this.CurrentValueAsString = e.Value.ToString();
      }
      
      @page "/Test3"
      <EditForm EditContext="@_editContext" OnValidSubmit="@HandleValidSubmit">
          <DataAnnotationsValidator />
          <ValidationSummary />
          <label class="form-label">First Name</label>
          <CustomInput class="form-control" @bind-Value="this._formModel.FirstName" Id="mycontrol"></CustomInput>
          <label class="form-label">First Name</label>
          <CustomInput class="form-control" @bind-Value="this._formModel.FirstName" Id="mydisabledcontrol" Disabled="true"></CustomInput>
          <div class=" m-2 p-2">
              <button type="submit" class="btn btn-primary">New Person</button>
          </div>
      
          <div class="p3-m-3">Value: @_formModel.FirstName</div>
      
      </EditForm>
      
      @code {
          private EditContext? _editContext;
          private FormModel _formModel;
      
          private void HandleValidSubmit()
          {
              // handler
          }
      
      
          private class FormModel
          {
              [StringLength(5)][Required] public string FirstName { get; set; }
          }
      
          protected override Task OnInitializedAsync()
          {
              _formModel = new FormModel();
              _editContext = new EditContext(_formModel);
              return base.OnInitializedAsync();
          }
      }
      
      咏叹调变化

      当输入有效/无效时,查看两个 html sn-ps。

      <input type="text" id="mycontrol" class="form-control" _bl_759b54c2-54a4-461f-8101-9661c9034c17>
      
      <input type="text" id="mycontrol" class="form-control" _bl_759b54c2-54a4-461f-8101-9661c9034c17 aria-invalid>
      

      【讨论】:

      • 感谢您花时间回答问题,但这并不能解决我遇到的问题,即即使输入值无效,也没有添加“无效”类。
      • 如果您设置并运行我的示例,您将看到 aria-invalid 出现和消失,因为 firstname 有效/无效。
      • aria-invalid 也被添加到我的中,无论它是有效还是无效,在我的问题中,我的意思是类不会改变以反映输入的无效/有效状态,这就是我需要。这样我就可以根据输入的有效/无效状态应用样式。
      • InputBase 根据控件的验证状态在AdditionalAttributes 属性中添加/删除“aria-invalid”。在我上面的代码中它是正确的,只有当字段被清空或包含超过 5 个字符时才添加它。您是说要根据控件的验证状态应用自定义样式吗?
      • 是在标准 InputText 上,如我上面的代码所示,根据模型验证应用了 validinvalid 类。默认情况下,Blazor 在 app.css 文件中为此提供了 CSS 样式。我的问题是问为什么无效和有效类不能根据我的自定义组件中的验证状态正确更改。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-02
      • 2011-07-08
      • 2019-03-03
      • 1970-01-01
      相关资源
      最近更新 更多