将FormControl传递给子组件-没有用于未指定名称的表单控件的值访问器

时间:2018-11-01 10:37:53

标签: angular angular-reactive-forms angular-forms

我有一个输入组件customInput,它创建一个经典的输入字段并为其添加一些布局香料,而无需附加逻辑。

我想将formControl传递给它,以将其绑定到它包含的输入中。

应按以下方式使用:

<form [formGroup]="form">
  <custom-input [formControl]="form.controls['control']"></custom-input>
</form>

内部自定义输入:

export class HidInputFieldComponent  {
   @Input() formControl: AbstractControl

   ...
}

<div class="container">
  <input [formControl]="formControl"/>
    <label>label</label>
</div>

现在,当我初始化组件时,我会得到

  

没有用于未指定名称的表单控件的值访问器

将控件记录到我的组件构造函数中,它是未定义的。

我做错了还是ControlValueAccessor周围没有办法?由于我实际上并不是在构建自定义控件(我仍然使用经典输入),所以这似乎很极端

4 个答案:

答案 0 :(得分:0)

使用 FormGroupDirective

  

此伪指令接受现有的FormGroup实例。然后它将   使用此FormGroup实例来匹配任何子FormControl,FormGroup,   和FormArray实例添加到子FormControlName,FormGroupName和   FormArrayName指令。

这样做,您可以从父级访问子级formControl

           

  @Component({
    selector: 'app-custom-input',
    templateUrl: './custom-input.html',
    viewProviders:[{ provide: ControlContainer, useExisting: FormGroupDirective}]
  })    
    export class HidInputFieldComponent  {
     constructor(private fcd:FormGroupDirective) {       
    }
    ngOnInit() {
        this.fcd.form.addControl('formControl',new FormControl(''));
    }
    }

    <div class="container">
      <input [formControl]="formControl"/>
        <label>label</label>
    </div>

答案 1 :(得分:0)

您也可以尝试实现ControlValueAccessor接口类。

@Component({
  selector: 'app-custom-input',
  templateUrl: './app-custom-input.component.html'
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      multi: true,
      useExisting: forwardRef(() => HidInputFieldComponent)
    }
  ]
})
export class HidInputFieldComponent implements OnInit, ControlValueAccessor {
  @Output() setDropdownEvent: EventEmitter<any> = new EventEmitter();

  ngOnInit() {}

  writeValue(value: any) {}

  propagateChange(time: any) {
    console.log(time);
  }

  registerOnChange(fn) {
    this.propagateChange = fn;
  }

  registerOnTouched() {}
}

答案 2 :(得分:0)

您不需要导入ControlValueAccessor或类似的东西即可实现。

您需要做的就是像这样将FormControl对象传递给子组件:

<form [formGroup]="form">
  <custom-input [control]="form.get('theControlName')">
  </custom-input>
</form>

这意味着您的自定义输入组件应如下所示:

import {Component, Input} from '@angular/core';
import {FormControl} from '@angular/forms';

@Component({
  selector: 'custom-input',
  templateUrl: './input.component.html',
  styleUrls: ['./input.component.scss']
})
export class InputComponent {
  @Input() control: FormControl;
}

和模板:

<input [formControl]="control">

就是这样。

如果您实现了这样的自定义输入,就不必将父formGroup引入子组件逻辑中,那么在那里就完全没有必要了(除非您需要对其进行某些操作或对表单的其余部分进行某些操作控件)。

此外,将FormControl对象传递给自定义输入将使您无需引用FormGroup即可访问它的属性,然后获取特定的控件,因为这是在父组件上完成的工作。

我希望这种解决方案有助于简化许多人的工作,因为制作这种自定义控件非常普遍。

答案 3 :(得分:0)

来自Johann Garrido的

this answer很好,但是它引入了额外的输入[control],在使用自定义组件时,您需要始终记住这些输入。

,它可以直接与ReactiveFormsModule绑定,因为它仅接受FormControl实例。

在我看来,更好的方法是实现ControlValueAccessor接口,但要利用一些变通办法以不重复控件处理:

export const NOOP_VALUE_ACCESSOR: ControlValueAccessor = {
  writeValue(): void {},
  registerOnChange(): void {},
  registerOnTouched(): void {}
};

并在包装表单控件的组件中使用NOOP_VALUE_ACCESSOR

@Component({
  selector: "wrapped-input",
  template: `
    <mat-form-field class="example-full-width">
      <mat-label>Wrapped input</mat-label>

      <!--We pass NgControl to regular MatInput -->
      <input matInput [formControl]="ngControl.control" />
    </mat-form-field>
  `
})
export class WrappedInput {
  constructor(@Self() @Optional() public ngControl: NgControl) {
    if (this.ngControl) {
      // Note: we provide the value accessor through here, instead of
      // the `providers` to avoid running into a circular import.
      // And we use NOOP_VALUE_ACCESSOR so WrappedInput don't do anything with NgControl
      this.ngControl.valueAccessor = NOOP_VALUE_ACCESSOR;
    }
  }
}

这样,Angular会认为WrappedInput的工作方式与实现ControlValueAccessor接口(例如MatInput)的任何其他组件一样。

,它将与ReactiveFormsModule和常规FormsModule一起使用。

WrappedInput可以这样使用:

<wrapped-input [formControl]="sourceControl"></wrapped-input>

这里是您可以玩的完整的堆叠闪电战: https://stackblitz.com/edit/angular-wrapped-form-control-example?file=src/app/app.ts