【问题标题】:How to trigger child component validators from parent component in Angular 2 using template forms如何使用模板表单从 Angular 2 中的父组件触发子组件验证器
【发布时间】:2017-10-08 01:07:30
【问题描述】:

我在使用 Angular 中的模板表单进行条件验证时遇到问题。我创建了一个自定义 EmailInputComponent:

<div class="form-group" provide-parent-form>
  <label for="email">Email<span *ngIf="required">*</span></label>
  <input id="email"
         class="form-control"
         name="email"
         type="email"
         [(ngModel)]="emailAddress"
         #email="ngModel"
         maxlength="255"
         validateEmail
         [required]="required ? '' : null"/>
  <error [model]="email" [referencedValue]="emailAddress"></error>
</div>

托管在父级 MyFormComponent 中:

<form #form="ngForm" name="form" (ngSubmit)="onSubmit($event)">
  <fieldset>
    <email [(emailAddress)]="model.email" [required]="emailRequired()"></email> 
    <!-- select component here -->
  </fieldset>    
  <button type="submit" [disabled]="!form.form.valid">Send</button>
</form>

该表单还包含一个 SelectComponent,用户可以在其中选择他们喜欢的联系方式。如果用户选择“email”,则必须输入email。

如您所见,父母 emailRequired 中存在一些逻辑 根据当前选择的首选联系方式动态计算电子邮件输入是否是强制性的功能。 每当这个选定的值发生变化时,我都需要以某种方式触发电子邮件输入验证器。我怎样才能做到这一点?

使用 @ViewChild 我设法从 MyFormComponent 中获得了 EmailInputComponent。但我现在不知道如何进行......

【问题讨论】:

  • 您是否尝试过使用AbstractControl#updateValueAndValidity?由于您将required 用作@Input,因此您可能希望将其添加到子组件的ngOnChanges 生命周期挂钩中。
  • 这与您的问题无关,但我建议您考虑使用反应形式,这样会更容易处理。只是一个善意的建议:)
  • 您的EmailInputComponent 是否实现了ControlValueAccessor?更多详情请见this answer
  • @GarthMason:不,我使用了github.com/angular/angular/issues/9600#issuecomment-317774127的解决方法
  • @AJT_82 我不喜欢反应形式附带的所有样板 TS 代码。这就是为什么我要坚持使用模板驱动的。

标签: javascript angular validation angular2-forms


【解决方案1】:

我认为您不需要在前面指定attr 来引用required 属性。

尝试简单,

 [required]="required ? '' : null"

如果它仍然不起作用,可能是因为“@Input”required 属性没有在 EmailInputComponent 中更新。因此,@naeramarth7 建议在 EmailInputComponent 的 ngOnChanges 挂钩中查找它并进行更新。

ngOnChanges(changes: SimpleChange) {
 for (let prop in changes) {
  if(prop === 'required') { 
   this.required = changes[prop].currentValue;
  }
 }
}

确保在使用时将implements OnChanges 添加到EmailInputComponent 声明中,并从email-input.component.ts 内的'@angular/core' 中导入SimpleChangeOnChanges

【讨论】:

  • 感谢您的帖子。你是对的 - 我不需要 attr 前缀。我编辑了我最初的帖子。然而,这不是我的观点。绑定到所需的属性效果很好。我真正想要实现的是触发电子邮件组件验证器。
【解决方案2】:

与此同时,我找到了解决方案。我的子组件现在引用了相应的 FormGroup。

<email [(emailAddress)]="model.email" 
       [formGroup]="form.form" 
       [required]="emailRequired()">
</email>

通过 FormGroup,您可以访问子组件实际的 FormControl 并在验证器标志的设置器中调用 updateValueAndValidity(在我的情况下为 set required):

import {Component, EventEmitter, Input, Output} from '@angular/core';
import {FormGroup} from '@angular/forms';

@Component({
  selector: 'email',
  templateUrl: './email.component.html',
  styleUrls: ['./email.component.css']
})
export class EmailInputComponent {

  private _emailAddress: string;

  public _required = true;

  @Input()
  private formGroup: FormGroup;

  @Output()
  emailAddressChange = new EventEmitter();

  constructor() { }

  @Input()
  get emailAddress(): string {
    return this._emailAddress;
  }

  set emailAddress(value: string) {
    this._emailAddress = value;
    this.emailAddressChange.emit(this._emailAddress);
  }

  @Input()
  get required(): boolean {
    return this._required;
  }

  set required(value: boolean) {
    this._required = value;
    // this is where the magic happens
    const refEmailControl = this.formGroup.controls.email;
    if (refEmailControl) {
      refEmailControl.updateValueAndValidity(); // updates the validity state      
      refEmailControl.markAsTouched(); // necessary in my case to make UI render error message
    }
  }
}

【讨论】:

    猜你喜欢
    • 2018-04-27
    • 2018-06-07
    • 2018-02-17
    • 2016-11-27
    • 1970-01-01
    • 2018-12-11
    • 2018-05-04
    • 2023-03-13
    • 2017-06-27
    相关资源
    最近更新 更多