Angular: 从指令访问 FormControl

Angular: access FormControl from Directive

我想通过自定义指令将验证器动态添加到我的 FormControl。

@Directive({
    selector: "[idNumber]",
})
export class IdNumberDirective implements OnInit {

    constructor(private formControl: FormControl) { }

    ngOnInit() {
        this.addValidators(this.formControl);
    }

    addValidators(formControl: FormControl) {
        formControl.setValidators(Validators.compose(
            [Validators.required,
            Validators.minLength(3),
            Validators.maxLength(8)
            ]
        ));
    }



<mat-form-field>
    <mat-label>{{label}}</mat-label>
    <input matInput
        [formControl]="idNumberFormControl"
        [placeholder]="placeholder"
</mat-form-field>


我不需要引用 nativeElement(通过 ElementRef)。
我想引用 formControl...
...并这样使用它:

// HTML with my custom directive 'idNumber' ////////
<custom-input-string
    idNumber 
    [name]="'idNumber'"
    [label]="Id Number"
    [placeholder]="">
</custom-input-string>

// TS ////////
@ViewChild(CustomInputStringComponent) child: CustomInputStringComponent;

ngAfterViewInit() {
    setTimeout(() => {
        this.child.insertIntoForm(this.signupForm);
    }, 0);
}


有什么想法吗?
谢谢大家

如果您使用 NgControl 和构造函数 DI 注入,我们可以有一个指令适用于来自 formControlName 或模板驱动表单中的反应表单的表单控件:

指令:

import { Directive } from "@angular/core";
import { NgControl } from "@angular/forms";

@Directive({
  selector: '[my-directive]'
})
export class MyDirective {
  constructor(private el: ElementRef, private control : NgControl) { }

}

下面是一个使用指令将验证器附加到表单控件的示例。

Stackblitz

请注意,使用它会导致您之前的所有验证器丢失。

constructor(
  // Get the control directive
  private control: NgControl
) { }
ngOnInit() {
  const abstractControl = this.control.control;
  abstractControl && abstractControl.setValidators([Validators.required]);
}
//TestAnythingsComponent.ts

import { Component, OnInit } from '@angular/core';
import { FormControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { IdNumberDirective } from '../directives/IdNumberDirective.directive';

@Component({
  selector: 'app-test-anythings',
  templateUrl: './test-anythings.component.html',
  styleUrls: ['./test-anythings.component.css'],
  providers:[IdNumberDirective]
})
export class TestAnythingsComponent implements OnInit {
  testForm: FormGroup;

  constructor(fb: FormBuilder, IdNumberDirective : IdNumberDirective) { 
    this.testForm = fb.group({
      idNumberFormControl : new FormControl(null,
          Validators.compose([
            Validators.required,
            Validators.minLength(3),
            Validators.maxLength(8),
          IdNumberDirective.customValidator()
          ])
        ),
    })
  }
}

//IdNumberDirective.ts

import { Directive, OnInit } from '@angular/core';
import { Validators, ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';

@Directive({
  selector: '[idNumber]'
})
export class IdNumberDirective implements OnInit {

  constructor() {

  }

  ngOnInit() {

  }

  customValidator(): ValidatorFn {
    Validators.nullValidator
    return (control: AbstractControl): ValidationErrors | null => {

      //any condition to check control value
      if (control.value != "Sachin") {
        //return key value pair of errors
        return { "customError": { inValid: true, errMsg: 'Invalid Value' } };
      }
      return null;
    }
  }
}


//test-anythings.component.html

<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre><code>    <form [formGroup]="testForm">
      <input idNumber formControlName="idNumberFormControl" />
      <div *ngIf="testForm.get('idNumberFormControl').invalid && testForm.get('idNumberFormControl').errors.customError.inValid"
        style="color:red">
        {{testForm.get('idNumberFormControl').errors.customError.errMsg}}
      </div>
    
      <button type="submit">submit</button>
    </form>

您可以通过 FormGroupDirective:

在指令中访问 FormGroup 和 FormControl

注意:在此示例中,我正在选择国家/地区。

import { FormGroupDirective } from "@angular/forms";

然后:

{
constructor(private fg: FormGroupDirective) { }


// Access the FormGroup
console.log('My FormGroup values: ', this.fg.value);

// Access the FormControl
console.log('The selectedCountryCtrl: ', this.fg.control.controls.selectedCountryCtrl);
console.log('The selectedCountryCtrl value: ', this.fg.control.controls.selectedCountryCtrl.value);

// Access the variable/object directly
console.log('My FormControl selectedCountry value: ', this.fg.value.selectedCountry);
}

最简单且 'cleanest' 的方法是使用 NG_VALIDATORS 提供商:

import { Directive } from '@angular/core'
import { NG_VALIDATORS ValidationErrors, Validator } from '@angular/forms'

@Directive({
  selector: '[myIdValidator]',
  providers: [
    { provide: NG_VALIDATORS, useExisting: IdValidatorDirective, multi: true }
  ],
})
export class IdValidatorDirective implements Validator {
  validate(control: AbstractControl): ValidationErrors | null {
    // your validation here
    return null
  }
}