Angular 角度:从指令访问FormControl

Angular 角度:从指令访问FormControl,angular,typescript,angular-directive,Angular,Typescript,Angular Directive,我想通过自定义指令将验证器动态添加到我的FormControl中 @Directive({ selector: "[idNumber]", }) export class IdNumberDirective implements OnInit { constructor(private formControl: FormControl) { } ngOnInit() { this.addValidators(this.formControl);

我想通过自定义指令将验证器动态添加到我的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>
@指令({
选择器:“[idNumber]”,
})
将类IdNumberDirective实现导出到NIT{
构造函数(私有formControl:formControl){}
恩戈尼尼特(){
this.addValidators(this.formControl);
}
addValidators(formControl:formControl){
formControl.setValidators(Validators.compose(
[验证器。必需,
验证器。最小长度(3),
Validators.maxLength(8)
]
));
}
{{label}}

如果您使用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) { }

}

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

请注意,使用它将导致丢失所有以前的验证器

constructor(
  // Get the control directive
  private control: NgControl
) { }
ngOnInit() {
  const abstractControl = this.control.control;
  abstractControl && abstractControl.setValidators([Validators.required]);
}
//TestAnythingsComponent.ts
从“@angular/core”导入{Component,OnInit};
从'@angular/forms'导入{FormControl,FormBuilder,FormGroup,Validators};
从“../directions/IdNumberDirective.directive”导入{IdNumberDirective};
@组成部分({
选择器:“应用程序测试任何东西”,
templateUrl:“./testanythings.component.html”,
styleUrls:['./testanythings.component.css'],
提供者:[IdNumberDirective]
})
导出类TestAnythingsComponent实现OnInit{
testForm:FormGroup;
构造函数(fb:FormBuilder,IdNumberDirective:IdNumberDirective){
this.testForm=fb.group({
idNumberFormControl:new FormControl(空,
验证器([
需要验证器,
验证器。最小长度(3),
验证程序。最大长度(8),
IdNumberDirective.customValidator()
])
),
})
}
}
//IdNumberDirective.ts
从'@angular/core'导入{指令,OnInit};
从'@angular/forms'导入{Validators,ValidatorFn,AbstractControl,ValidationErrors};
@指示({
选择器:“[idNumber]”
})
将类IdNumberDirective实现导出到NIT{
构造函数(){
}
恩戈尼尼特(){
}
customValidator():验证器fn{
验证器。空验证器
返回(控件:AbstractControl):ValidationErrors | null=>{
//检查控制值的任何条件
if(control.value!=“Sachin”){
//返回错误的键值对
返回{“customError”:{inValid:true,errMsg:'inValid Value'};
}
返回null;
}
}
}
//test-anythings.component.html

{{testForm.get('idNumberFormControl').errors.customError.errMsg}}
提交

Hi@Suresh,谢谢你的建议,但我需要更详细的解释。我能做到吗?this.addValidators(this.control);这样行吗?PS:我不使用,也永远不会使用“模板驱动表单”。我们可以使用NgControl通过DI获取对表单控件实例的引用。您可以使用该实例访问表单控件方法。您可以用更多代码更新您的答案吗?另外-您的建议中的“private el:ElementRef”有什么意义n?嗨,OneEvent不是每次都会在FormControl的valueChanges上触发吗?我的意思是,当用户在FormControl中集中注意力时,不是每次按下任何键时都会触发此事件吗?难道没有办法在指令的OnInit方法中检查和设置这些验证器吗?谢谢。是的,它会在每次按键时触发,但是函数中的条件阻止多次设置验证器。必须这样做,因为构造函数不知道控件。您也可以使用ngOnInit(),正如我在其中使用更新我的答案一样(因为它确实更清楚!)太棒了!这正是我想要的!谢谢!这个答案非常有效,但我认为主要方面(使用
NgControl
而不是OP的
FormControl
)太有价值了,不能停留在外部链接中(Stackblitz)。我建议我们把这部分直接放在答案中,就像@Suresh在他的答案中一样。亲爱的Sachin,你能对你的代码发表一些评论以帮助理解你的方法吗?嗨,Artem,看看我上面的解决方案,请输入“Sachin”以消除错误消息,我已经尽了最大努力,我是angular的新手。谢谢。
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

    <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>