创建可重用的 FormGroup [英] Create a reusable FormGroup

查看:22
本文介绍了创建可重用的 FormGroup的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道创建自定义控件作为组件,但我不知道如何创建自定义.

I am aware of creating custom controls as components, but I can't figure out how to create custom groups.

同样我们可以通过实现ControlValueAccessor并使用像<my-cmp formControlName="foo"></my-cmp>这样的自定义组件,对于一个?

The same we can do this by implementing ControlValueAccessor and using a custom component like <my-cmp formControlName="foo"></my-cmp>, how can we achieve this effect for a group?

<my-cmp formGroupName="aGroup"></my-cmp>

两个非常常见的用例是 (a) 将一个长表单分成多个步骤,每个步骤在一个单独的组件中,以及 (b) 封装一组出现在多个表单中的字段,例如地址(国家/地区组,州、城市、地址、建筑编号)或出生日期(年、月、日).

Two very common use-cases would be (a) separting a long form into steps, each step in a separate component and (b) encapsulating a group of fields which appear across multiple forms, such as address (group of country, state, city, address, building number) or date of birth (year, month, date).

Parent 有以下使用 FormBuilder 构建的表单::>

Parent has the following form built with FormBuilder:

// parent model
form = this.fb.group({
  username: '',
  fullName: '',
  password: '',
  address: this.fb.group({
    country: '',
    state: '',
    city: '',
    street: '',
    building: '',
  })
})

父模板(为简洁起见不可访问且无语义):

Parent template (inaccessible and non-semantic for brevity):

<!-- parent template -->
<form [groupName]="form">
  <input formControlName="username">
  <input formControlName="fullName">
  <input formControlName="password">
  <address-form-group formGroup="address"></address-form-group>
</form>

现在这个 AddressFormGroupComponent 知道如何处理一个包含这些特定控件的组.

Now this AddressFormGroupComponent knows how to handle a group which has these specific controls inside of it.

<!-- child template -->
<input formControlName="country">
<input formControlName="state">
<input formControlName="city">
<input formControlName="street">
<input formControlName="building">

推荐答案

rusev 的回答,那就是注入ControlContainer.

事实证明,如果您将 formGroupName 放在一个组件上,并且如果该组件注入 ControlContainer,您将获得对包含该表单的容器的引用.从这里开始很容易.

Turns out that if you place formGroupName on a component, and if that component injects ControlContainer, you get a reference to the container which contains that form. It's easy from here.

我们创建一个子表单组件.

We create a sub-form component.

@Component({
  selector: 'sub-form',
  template: `
    <ng-container [formGroup]="controlContainer.control">
      <input type=text formControlName=foo>
      <input type=text formControlName=bar>
    </ng-container>
  `,
})
export class SubFormComponent {
  constructor(public controlContainer: ControlContainer) {
  }
}

注意我们如何需要一个包装器来包装输入.我们不想要一个表单,因为它已经在一个表单中了.所以我们使用 ng-container.这将从最终的 DOM 中剥离,因此没有不必要的元素.

Notice how we need a wrapper for the inputs. We don't want a form because this will already be inside a form. So we use an ng-container. This will be striped away from the final DOM so there's no unnecessary element.

现在我们可以使用这个组件了.

Now we can just use this component.

@Component({
  selector: 'my-app',
  template: `
    <form [formGroup]=form>
      <sub-form formGroupName=group></sub-form>
      <input type=text formControlName=baz>
    </form>
  `,
})
export class AppComponent  {
  form = this.fb.group({
    group: this.fb.group({
      foo: 'foo',
      bar: 'bar',
    }),
    baz: 'baz',
  })

  constructor(private fb: FormBuilder) {}
}

您可以看到现场演示 在 StackBlitz 上.

You can see a live demo on StackBlitz.

这在几个方面比 rusev 的答案有所改进:

This is an improvement over rusev's answer in a few aspects:

  • 没有自定义groupName 输入;相反,我们使用 Angular 提供的 formGroupName
  • 不需要 @SkipSelf 装饰器,因为我们不是注入父控件,而是我们需要的
  • 没有尴尬的 group.control.get(groupName) 它会去父级以抓取自己.
  • no custom groupName input; instead we use the formGroupName provided by Angular
  • no need for @SkipSelf decorator, since we're not injecting the parent control, but the one we need
  • no awkward group.control.get(groupName) which is going to the parent in order to grab itself.

这篇关于创建可重用的 FormGroup的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆