angular – 通过查询组件的模板来获取FormControl实例

前端之家收集整理的这篇文章主要介绍了angular – 通过查询组件的模板来获取FormControl实例前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个自定义FormFieldComponent,它封装了表单字段的 HTML错误显示逻辑:
@Component({
  selector: 'field',template: `
    <div class="form-group">
      <label class="control-label">{{label}}</label>
      <ng-content></ng-content>  <!-- Will display the field -->
      <!-- Here,put error display logic -->
    </div>
  `
})
export class FormFieldComponent {
  @Input() label: string;  // Field label
  @Input() theControl: FormControl;  // Current form control,required to display errors
}

在FormFieldComponent中,我需要一个FormControl实例来显示错误.

我的表单看起来像这样:

<form [formGroup]="myForm">
  ...
  <field label="Title" [theControl]="myForm.get('title')">
    <input type="text" formControlName="title">
  </field>
  ...
</form>

但我对上面的代码并不完全满意.如您所见,我在两个位置指定字段的键:在[theControl]输入属性和formControlName指令中.

如果我能写的话,代码会更简洁:

<field label="Title">
  <input type="text" formControlName="title">
</field>

注意[theControl]输入属性是如何消失的. FieldComponent应该能够获得它包含的FormControl实例,但是如何实现呢?

我已经尝试使用@ContentChildren装饰器来查询FormControl指令的组件模板,但它不起作用:

export class FormFieldComponent {
  @ContentChildren(FormControlDirective) theControl: any;
}

另一种选择是将字段的键作为输入传递给FormFieldComponent,然后让组件使用该键:

>以编程方式将formControlName指令应用于它包含的字段.
>获取其父级< form>,访问相应的FormGroup实例,并从中提取FormControl实例.

简短的回答:你不能

你不能. (好吧,也许你可以,但它会是hacky!)

答案很长:你不能,但……

FormControl不可注射.指令是可注入的,但是,您必须处理formControlName,ngModel,formControl等,并且它们不能从包装组件访问,但它的子代…

对于你的情况,你可以试试@ContentChildren(FormControlName)theControl:any;因为你的代码中没有暗示FormControlDirective,但你无论如何都无法访问FormControl(属性_control是内部的,所以它会是一个hack)…

因此,您应该坚持从处理FormGroup的组件中管理错误.

但是,如果你想显示一个自定义输入(不会显示错误信息,但能够显示此输入处于错误状态(主机元素将获得ng-valid,ng-invalid类,所以它只是你可以通过实施ControlValueAccessor来实现这一点.

A bridge between a control and a native element.

A ControlValueAccessor abstracts the operations of writing a new value to a DOM element representing an input control.

这意味着实现此接口的指令/组件可以与ngModel,formControl等一起使用…

例如:< my-component [(ngModel)] =“foo”>< / my-component>

它不是你问题的确切复制品,但是这个实现为我解决了同样的问题:

export const INPUT_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,useExisting: forwardRef(() => InputComponent),multi: true
};

@Component({
  selector: "field",template: `<!--put anything you want in your template-->
            <label>{{label}}</label>
            <input #input (input)="onChange($event.target.value)" (blur)="onTouched()" type="text">`,styles: [],providers: [INPUT_VALUE_ACCESSOR]
})
export class InputComponent implements ControlValueAccessor {
  @ViewChild("input")
  input: ElementRef;
  @Input()
  label:string;
  onChange = (_: any) => { };
  onTouched = () => { };

  constructor(private _renderer: Renderer) { }

  writeValue(value: any): void {
    const normalizedValue = value == null ? "" : value;
    this._renderer.setElementProperty(this.input.nativeElement,"value",normalizedValue);
  }

  registerOnChange(fn: (_: any) => void): void {
      this.onChange = fn;
  }
  registerOnTouched(fn: () => void): void { this.onTouched = fn; }

  setDisabledState(isDisabled: boolean): void {
    this._renderer.setElementProperty(this.input.nativeElement,"disabled",isDisabled);
  }
}

那你就可以:

<field label="Title" formControlName="title"></field>

猜你在找的Angularjs相关文章