将formControlName转发到Angular中的内部组件

时间:2018-10-19 13:13:54

标签: angular angular-reactive-forms

我有一个包装到<some-input>的自定义控件组件<ext-some-input> SomeInput 已封装,具有自己的API并支持反应形式。 ExtSomeInput 被创建为 SomeInput 上的高级包装。

我有以下html:

<form [formGroup]="form">
    <ext-some-input formControlName="name">
</form>

ExtSomeInput 的html:

<some-input formControlName="_???_"></some-input>

问题是如何将 formControlName 转发到内部的 SomeInput 组件?我需要将窗体和内部formControl绑起来。这可能吗?

已编辑:

我创建了一个带有以下问题的stackblitz项目:here

6 个答案:

答案 0 :(得分:2)

  

您可以在组件ext-some-input中创建@Input

ext-some-input.ts

@Input 
formControlName

ext-some-input.html

<some-input [formControlName]="formControlName"></some-input>

答案 1 :(得分:2)

您的内部组件可以使用@Input formControlName,但不能立即使用:

  

错误:formControlName必须与父formGroup指令一起使用。

为了将控件与父FormGroup绑定在一起,您可以定义viewProvider,如下所示:

import { Component, Input, OnInit} from '@angular/core';
...
import { ControlContainer, FormGroupDirective } from '@angular/forms';

@Component({
  ...
  viewProviders: [
    {
      provide: ControlContainer,
      useExisting: FormGroupDirective
    }
  ]
})
export class DateWrapperComponent implements OnInit {
    @Input() formControlName: string;
}

Forked Stackblitz

答案 2 :(得分:1)

我遇到了几乎相同的情况和问题。托德·莫托(Todd Motto)的article令我欣慰。

他的方法是将formGroup作为父项提供给自定义输入组件。然后,可以从该组件将控件(验证器)和formControlName(值)绑定到输入标签。

通常,榜样会自己说话。

表单组件ts

// Reactive Forms
form: FormGroup;    

constructor(private formBuilder: FormBuilder) { }

ngOnInit() {
  // Form structure and validators
  this.form = this.formBuilder.group({
    'user' : this.formBuilder.group({
      'username' : ['', Validators.required],
      'email' : ['', [Validators.required, Validators.email]]
    }),
    'identity' : this.formBuilder.group({
      'firstname' : ['', Validators.required],
      'lastname'  : ['', Validators.required],
      'address' : this.formBuilder.group({
        'street' : ['', Validators.required],
        'city'  : ['', Validators.required],
      })
    })
  });        
}

onSubmit() {
    // Get object with same structure as form but only with values
    console.log(this.form.value);
    alert('Form is ' + (this.form.invalid ? 'invalid' : 'valid'));
}

表单组件html

<form [formGroup]="form" (ngSubmit)="onSubmit()">
    <form-text [formGroupParent]="form.get(['user'])"
               [formGroupControlName]="'username'">
    </form-text>
    <form-text [formGroupParent]="form.get(['user'])"
               [formGroupControlName]="'email'">
    </form-text>
    <hr>
    <form-text [formGroupParent]="form.get(['identity'])"
               [formGroupControlName]="'firstname'">
    </form-text>
    <form-text [formGroupParent]="form.get(['identity'])"
               [formGroupControlName]="'lastname'">
    </form-text>
    <hr>
    <form-text [formGroupParent]="form.get(['identity','address'])"
               [formGroupControlName]="'street'">
    </form-text>
    <form-text [formGroupParent]="form.get(['identity','address'])"
               [formGroupControlName]="'city'">
    </form-text>
    <button type="submit">Submit</button>
</form>

自定义输入组件ts(表单文本)

// Needed to bind formControlName
@Input() formGroupParent: FormGroup;
@Input() formGroupControlName: string;
// FormControl store validators
control: FormControl;

ngOnInit() {
    // Fetch Form control (validator) from FormGroup parent
    this.control = <FormControl>this.formGroupParent.get(this.formGroupControlName);
}

自定义输入组件html(表单文本)

<ng-container [formGroup]="formGroupParent">
  <label>{{formGroupControlName}}</label> 
  <input type="text" formControlName="{{formGroupControlName}}">
</ng-container>

答案 3 :(得分:0)

我认为您实际上正在寻找比input更复杂的东西。

如果您要创建自定义输入,则可以创建一个类,该类将是ControlValueAccessor(自定义表单控件)。

请查看以下文章,该文章的确有充分的解释:

https://alligator.io/angular/custom-form-control

答案 4 :(得分:0)

我遇到了类似的情况,我不想将formControlName传递给包装器组件。解决此问题的首选方法是仅重用包装器组件中从父表单传递的formGroup。您可以通过在ExtSomeInput组件的构造函数中注入ControlContainer来做到这一点:

ParentForm.component.html

<form [formGroup]="form">
  <ext-some-input controlName="name">
</form>

ExtSomeInput.component.ts

// pass the formControlName as string to wrapper
@Input public controlName: string;
public form: FormGroup;

constructor(public controlContainer: ControlContainer) {}

ngOnInit() {
  this.form = <FormGroup>this.controlContainer.control;
}

ExtSomeInput.component.html

// use ng-container to omit this from the DOM
<ng-container [formGroup]="form">
  // wrapper markup here
  <some-input [formControlName]="controlName"></some-input>
</ng-container>

答案 5 :(得分:0)

嘿,在这里第二个答案,因为我们在工作时采用了一种通用方法,该方法是作为开源库发布的=)。

您可以在这里找到它:https://github.com/cloudnc/ngx-sub-form

它应该可以帮助您管理: -嵌套表格 -具有多态数据的表格 -更好的打字

所有内容都在自述文件中进行了说明,/ src文件夹中提供了完整的示例。 (lib实际上是在projects / ngx-sub-form中)。

此处也提供了现场演示:https://cloudnc.github.io/ngx-sub-form