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

sko*_*enb 3 angular angular-reactive-forms

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

我有以下HTML:

<form [formGroup]="form">
    <ext-some-input formControlName="name">
</form>
Run Code Online (Sandbox Code Playgroud)

ExtSomeInput的html:

<some-input formControlName="_???_"></some-input>
Run Code Online (Sandbox Code Playgroud)

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

编辑:

我创建了这个问题的stackblitz项目:这里

yur*_*zui 6

您的内部组件可以使用,@Input controlName但无法立即使用:

错误: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() controlName: string;
}
Run Code Online (Sandbox Code Playgroud)

分叉的Stackblitz

  • 非常感谢!这绝对是我需要的。我将通过强制性方式了解`viewProviders` (3认同)
  • 只是想为那些迷惑于此答案的人提供一些注意事项...虽然可以,但是如果您使用formControlName作为输入变量名称,则会在控制台中出现错误。只需为中间组件使用其他输入变量名称,例如“ controlName”。 (2认同)
  • 这似乎有效,但是一旦您检查控制台,您会发现以下错误:“错误错误:没有名称为“某天”的表单控件的值访问器”。请。修复,否则其他用户会发现一个有错误的示例。 (2认同)

Cam*_*lle 6

我有几乎相同的场景和问题。托德·莫托的这篇文章让我松了口气。

他的方法是将 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'));
}
Run Code Online (Sandbox Code Playgroud)

表单组件 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>
Run Code Online (Sandbox Code Playgroud)

自定义输入组件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);
}
Run Code Online (Sandbox Code Playgroud)

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

<ng-container [formGroup]="formGroupParent">
  <label>{{formGroupControlName}}</label> 
  <input type="text" formControlName="{{formGroupControlName}}">
</ng-container>
Run Code Online (Sandbox Code Playgroud)