繁体   English   中英

如何在带有嵌套组件的表单中实现自动表单验证?

[英]How to implement automatic form validation in form with nested component?

在Angular 4应用程序的组件中考虑以下简单示例。 它显示了带有两个输入字段的简单HTML表单。 一个输入字段是直接实现的,第二个字段在子组件中:

<form #personForm="ngForm">
    <input type="text" required name="firstname [(ngModel)]="firstname"/>
    <app-smart-input required [(model)]="lastname"></app-smart-input>
    <button [disabled]="personForm.valid === false">Send</button>
</form>

子组件的定义如下:

import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";

@Component({
    selector: "app-smart-input",
    templateUrl: "./smart-input.component.html",
    styleUrls: ["./smart-input.component.css"]
})
export class SmartInputComponent {

    ////////////////
    // PROPERTIES //
    ////////////////

    @Input() model: string;
    @Output() modelChange: EventEmitter<string> = new EventEmitter<string>();

    @Input("required") required: boolean = false;

    /////////////
    // METHODS //
    /////////////

    updateChanges() {
        this.modelChange.emit(this.model);
    }

}

使用以下html:

<input type="text" [required]="required" [(ngModel)]="model" (ngModelChange)="updateChanges()" />

现在,更新模型可以正常工作( firstnamelastname由用户输入按预期定义)。

我要实现的是,除非两个字段都填写,否则按钮将被禁用。请注意<input>实现中的required标志,因此该值不应为null / undefined。

但是不幸的是,现在只有在firstname定义不正确的情况下才禁用该按钮。 但是表格并不关心lastname

我将如何实现?

注意: Angular 2创建带有嵌套组件的反应式是模拟的,但是我使用模板驱动的形式,而不是反应式。 但是它可能可以以某种方式进行修改吗?

如果希望SmartInputComponent作为Angular Form的一部分参与,则需要实现ControlValueAccessor

这意味着为自定义组件提供一种使更改在其与父窗体之间传播的方式。 这是一个以SmartInputComponent为基础的实现。

import { Component, OnInit, Input, Output, EventEmitter, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'

@Component({
  selector: 'app-smart-input',
  templateUrl: './smart-input.component.html',
  styleUrls: ['./smart-input.component.css'],
  providers:[ { 
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => SmartInputComponent),
    multi: true
  }]
})
export class SmartInputComponent implements ControlValueAccessor {

  @Input() model: any;

  onChange = (_: any) => {};
  onTouched = () => {};

  writeValue(obj: any): void {
    if (obj !== undefined) { 
      this.model = obj;
    }
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState?(isDisabled: boolean): void {
    //TODO: enabled/disable your input field if you need to
  }

  updateChanges(val) {
     this.onChange(val);
  }

  updateBlur(){
    this.onTouched();
  }
}

使用如下模板:

<input type="text" (input)="updateChanges(myTextBox.value)" (blur)="updateBlur()" #myTextBox [value]="model"/>

然后,在使用您的组件时,让它以标准控件(Angular为您提供ControlValueAccessor实现)的形式参与。

<form #personForm="ngForm">
  <input type="text" required name="firstname" [(ngModel)]="firstname" name="firstName" />
  <app-smart-input required [(ngModel)]="lastname" name="secondName"></app-smart-input>
  <button [disabled]="personForm.valid === false">Send</button>

  {{personForm.value | json}}

</form>

如果运行此表单,您将看到personForm现在同时捕获了名字和名字值。

另请参阅ControlValueAccessor上的Angular文档

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM