【问题标题】:Angular 9 - Validate child input component using built-in Ng directivesAngular 9 - 使用内置 Ng 指令验证子输入组件
【发布时间】:2021-07-31 04:29:52
【问题描述】:

我目前有一个文本控件input 组件,用作我的表单的输入字段。我正在为我需要的每条输入数据重复使用它,例如姓名、邮箱、密码等

我已将组件设置为采用 requiredminLengthmaxLength(目前不显示错误,这是我的问题的一部分),并且还希望他们使用内置的 Angular 指令验证:原始、脏、触摸等,然后将在父表单组件中显示验证消息。

我无法弄清楚如何将这些指令应用于子组件的实例,因为它似乎没有到达输入字段本身,我需要将不同的指令应用于不同的实例 例如。我需要 Name 不包含数字,但我需要 Password 来包含数字,因此使用不同的指令。

text-control.component.html

<input #textControlInput readonly="{{getReadOnly()}}" className="{{getCSSClasses()}}" [id]="id" [name]="name"
      [value]="modelValueDisplay" [type]="type" [minLength]="minLength" [maxLength]="maxLength" [size]="size"
      [placeholder]="placeholder" [required]="required" (input)="onChange()" (change)="onChange()"  />

text-control.component.ts

import {
  Component,
  EventEmitter,
  Input,
  Output,
  ViewChild,
  ElementRef,
} from '@angular/core';

@Component({
  selector: 'app-text-control',
  templateUrl: './text-control.component.html',
  styleUrls: ['./text-control.component.scss'],
})
export class TextControlComponent  {
  @Input() className: string;
  @Input() disabled = false;
  @Input() form: string;
  @Input() id: string;
  @Input() minLength: number;
  @Input() maxLength: number;
  @Input() name: string;
  @Input() pattern: string;
  @Input() placeholder: string;
  @Input() suffix: string;
  @Input() size = 25;
  @Input() type = 'text';
  @Input() value: string;
  @Input() public required = false;

  @ViewChild('textControlInput') textControlInput: ElementRef;

  public label: string;
  touched = false;

  constructor() {}

  ngOnInit() {}

  ngAfterViewInit() {}

  getCSSClasses() {
      return 'TextControl' + (this.className ? ' ' + this.className : '')
        + (this.multiLine ? ' multiLine' : '') + (this.disabled ? ' disabled' : '') ;
  }

}

parent.component.html

<app-text-control id="{{idPrefix}}firstName" name="{{idPrefix}firstName" [type]="'text'" [readOnly]="readOnly"
          className="g-mb-1" [size]="15" [(ngModel)]="loginDetails.firstName" [placeholder]="'First Name'"
          required="true" minLength="3" maxLength="100" #firstName=ngModel>
        </app-text-control>

parent.component.ts

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

@Component({
  selector: 'app-form-login-details',
  templateUrl: './form-login-details.component.html',
  styleUrls: ['./form-login-details.component.scss'],
})
export class FormLoginDetailsComponent implements OnInit {
  @Input() readOnly: boolean;
  @Input() idPrefix = '';
  @Input() loginDetails = new LoginDetails();
  @Output() loginDetailsChange = new EventEmitter<LoginDetails>();
  @Output() selectChange = new EventEmitter<any>();

  constructor() {}

  ngOnInit() {}


【问题讨论】:

    标签: javascript html angular typescript forms


    【解决方案1】:

    模板驱动的表单不能这样工作。首先,您需要将viewProviders 添加到您的子组件,以便它知道这是一个表单字段:)

    viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
    

    那么...您不能在子标签上添加[(ngModel)]。 NgModel 只处理(表单)字段、输入等。因此必须将其添加到子组件中。 #firstName=ngModel 也是如此。如果我们将模型和名称传递给子项,我们甚至实际上都不需要它……这很好,因为您不能动态创建模板引用。

    如此简化的代码示例(您应该努力实现,以便于调试,代码中有很多噪音):

    <form #f="ngForm">
      <app-text-control [required]="true" [name]="name" [model]="null"></app-text-control>
    </form>
    

    如果您想要输入的一些初始值,请将其添加到 model。我现在刚刚通过null

    然后是子组件(包括模板):

    @Component({
      selector: 'app-text-control',
      template: `
        <input [(ngModel)]="model" [name]="name" [required]="required"/>
      `,
      viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
    })
    export class TextControlComponent {
      @Input() model: string;
      @Input() name: string;
      @Input() public required = false;
    }
    

    在此示例中,您可以看到我从父级传递给子级的唯一验证器是 required。你可以尽可能多地通过:)

    这里有一个 STACKBLITZ 供您参考。

    最后……离题但很重要! ;)

    如果您的表单变得更复杂...例如像子组件,我真的建议您研究反应式表单:) 您只需将表单控件传递给子组件,其他所有内容都会被采用自动照顾!表单控件将包括值、验证等,所有内容都在一个包中!只是一个简短的离题建议;)

    【讨论】:

      猜你喜欢
      • 2016-12-13
      • 1970-01-01
      • 2020-03-21
      • 2020-06-18
      • 2016-07-09
      • 1970-01-01
      • 2013-03-04
      • 2012-08-16
      相关资源
      最近更新 更多