Angular 表单和指令的一个小技巧

2025-06-04

Angular 表单和指令的一个小技巧

想象一下,你想在应用程序的多个地方使用一个表单。表单具有相同的布局,但验证方式却不同。

在我们的案例中,此表单用于多步骤流程,并且每一步都会变得更加严格。您能保持DRY原则吗?我们遇到了这个问题,并提出了以下解决方案。

表格

举个例子,我们来看一个简单的表单,表单中包含一个人的姓名、联系方式和过敏史。
一开始只需要填写姓名。之后,我们会逐步添加此人的其他信息。

@Component({
  selector: 'person',
  template: `
    <div [formGroup]="form">
      <div>
        <label>Name</label>
        <input type="text" formControlName="name" />
      </div>

      <div>
        <label>Contact info</label>
        <input type="text" formControlName="contactInfo" />
      </div>

      <div>
        <label>Allergies</label>
        <input type="text" formControlName="allergies" />
      </div>

      <strong>{{ form.valid ? 'valid' : 'invalid' }}</strong>
    </div>
  `,
})
export class PersonComponent {
  form = this.formBuilder.group({
    name: ['', Validators.required],
    contactInfo: [''],
    allergies: [''],
  })

  constructor(private formBuilder: FormBuilder) {}
}
Enter fullscreen mode Exit fullscreen mode

默认情况下,我们将此人的姓名设为必填字段。

该指令

通过使用 Angular 指令,我们可以注入组件实例,从而访问表单。在本例中,我们可以修改表单的验证方式,并让更多字段成为必填字段。

@Directive({
  selector: 'person[stage-one]',
})
export class StageOneDirective {
  constructor(host: PersonComponent) {
    host.form.get('contactInfo').setValidators([Validators.required])
  }
}
Enter fullscreen mode Exit fullscreen mode

为了确保指令能够注入PersonComponent,我们必须使该指令特定于 Person 表单。为此,我们可以使用组件的选择器作为前缀,并在其后附加指令名称,即person[stage-one]。这样,只有当指令作为 Person 组件的属性添加时,才能使用该指令。
由于 Person 组件的表单设置为公共,因此我们可以在指令内部访问表单。如果我们可以访问表单,我们就可以访问表单字段及其验证器。

我们可以使用相同的方法来创建更严格的验证。

@Directive({
  selector: 'person[stage-two]',
})
export class StageTwoDirective {
  constructor(host: PersonComponent) {
    host.form.get('contactInfo').setValidators([Validators.required])
    host.form.get('allergies').setValidators([Validators.required])
  }
}
Enter fullscreen mode Exit fullscreen mode

用法

为了使这个小例子完整,这就是你将如何将 person 组件与另一个组件中的指令一起使用或不一起使用。

<!-- Only the name is required -->
<person></person>

<!-- The name and the contactInfo are required -->
<person stage-one></person>

<!-- All fields are required -->
<person stage-two></person>
Enter fullscreen mode Exit fullscreen mode

我发现这是一个与控制值访问器相结合的干净解决方案,正如在企业环境中使用 Angular 表单中讨论的那样。

在下面的闪电战中尝试一下这个例子

文章来源:https://dev.to/angular/a-little-trick-with-angular-forms-and-directives-2mep
PREV
针对 Angular 的自以为是的编码风格指南,使用正确的工具补充正确的风格指南。
NEXT
使用 First Timers Bot 自动处理新贡献者问题