Angular:在 NgForm 的自定义输入组件中调用 markAsDirty()

Posted

技术标签:

【中文标题】Angular:在 NgForm 的自定义输入组件中调用 markAsDirty()【英文标题】:Angular: Call markAsDirty() in Custom Input Component from NgForm 【发布时间】:2017-09-24 05:07:58 【问题描述】:

我实现了一个自定义组件,它是 NgModel 输入的包装器。我将它们与 ControlValueAccessor 连接起来。它运行良好,我可以轻松地从我的父组件访问值。

但是,如果我尝试调用 markAsDirty(),所触摸的标志只会在我的组件上发生变化,它对我在组件内的输入没有影响。我举个例子:

// Parent Component
onSubmit(form: NgForm) 
    this.form.controls.registerEmail.markAsDirty();


// Thats how the component looks like in my form:
<form #form="ngForm" (ngSubmit)="onSubmit(form)" [ngClass]="'has-error': !form.valid">
    <form-text label="E-Mail" name="registerEmail" email required placeholder="" [(ngModel)]="eMail"></form-text>
</form>

// Result
<form-text label="E-Mail" name="registerEmail" class="ng-untouched ng-invalid ng-dirty">
    <label for="form-text-2">E-Mail</label>
    <input class="input-control invalid ng-untouched ng-pristine ng-invalid" type="text" id="form-text-2">
</form-text>

您可以看到表单文本具有“ng-dirty”类,内部的输入保持原始状态。

为了实现我的自定义组件,我使用了您在网络上找到的许多说明之一。这是我用过的:angular2 custom form control with validation json input

我想在按下提交按钮时将每个输入字段标记为脏。因为我的验证出现了,所以当你模糊输入时。

我发现我的组件从 ControlValueAccessor 继承存在问题。我的组件和我的 NgForm 之间的唯一联系是通过它的 NgModel。 NgForm 可以将我的组件用作 FormControl,因为它有自己的 NgModel。在事件中,可以在两个方向上传递值。但是使用 markAsDirty() 或 markAsTouched() 之类的方法是不可能的。在组件内部没有问题。但是我的 NgForm 无法真正访问组件。仅适用于 NgModel。

有什么方法可以实现吗?我认为这并不难弄清楚,但我为此苦苦挣扎了很长时间。我目前唯一的解决方案是使用 jQuery 遍历每个输入以触发焦点。必须有一个更清洁的解决方案。

谢谢

【问题讨论】:

我也有同样的问题。有关于这个问题的消息吗? 如果不起作用,请将formControl 添加为输入组件的输入并调用方法。 &lt;form-text [control]="form.controls.eMail"&gt;。我们遇到了类似的问题,这是最实用的方法,因为子输入组件除了输入之外,不知道其父组件的任何内容。 @mchl18 你能解释一下或提供一个示例代码吗?这个问题快把我逼疯了 【参考方案1】:

您可以在实现ControlValueAccessor 的组件中传递表单的dirty 属性作为输入,然后使用ReactiveFormsModuleFormControl 更新您的内部输入的状态。

保存表单的组件:

<form #myForm="ngForm" (submit)="onSubmit($event)">
    <my-input name="my-input" [(ngModel)]="myInput" [formDirty]="myForm.dirty"></my-input>
    <button type="submit">Submit</button>
</form>

然后在实现ControlValueAccessor的组件中:

  ngOnChanges( formDirty : SimpleChanges) 
    if (formDirty.currentValue) 
      this.inputCtrl.markAsDirty();
     else 
      this.inputCtrl.markAsPristine();
    
  

Here you can find the relevant snippet.

【讨论】:

谢谢大佬,终于轻松了。我使用 [formSubmitted]="myForm.submitted" 在表单提交后显示错误消息。【参考方案2】:

当您希望控件状态设置为已触摸时,您需要从组件内部调用 onTouched() (this._onTouchedCallback)。 this._onChangeCallback 也一样

例如通过将 (ngModelChange)="onTouched(value)" 添加到 my-custom-input 中的输入标签

复制自: https://github.com/angular/angular/issues/10151

【讨论】:

【参考方案3】:

问题是当脏状态改变时没有简单的方法来获得任何通知。见https://github.com/angular/angular/issues/10887。

辅助指令:

@Directive(
  selector: 'my-input'
)
export class MagickDirective implements DoCheck 
  constructor(private control:NgModel)
  
  ngDoCheck(): void 
    //you can do whatever you want
    if(this.control.dirty) 
      (this.control.valueAccessor as MyInputComponent).setDirty(true);
    
  

【讨论】:

以上是关于Angular:在 NgForm 的自定义输入组件中调用 markAsDirty()的主要内容,如果未能解决你的问题,请参考以下文章

自定义 angular2 表单输入组件,在组件内具有两种方式绑定和验证

我可以在 Angular 4 的同一个组件中使用两个 ngForm 吗?

Angular2 2方式绑定中同名的自定义输入和输出

Angular2 - 使用旧数据的自定义验证器

Angular NgForm:重置确切的表单字段值不会使其有效

ngForm 或 [formGroup] 在 formly 包装器中是未知的