使用验证器创建自定义FormControl

时间:2019-06-11 18:51:31

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

我创建了一个使用Material设计的组件(AComponent),我希望将其用作我的“反应式表单”(在AppComponent中)的formControl。 我已经在此组件(AComponent)中实现了ControlValueAccessor

export class AComponent implements ControlValueAccessor {
  fm = new FormControl();

  constructor(private ngControl: NgControl) {
    ngControl.valueAccessor = this;

    this.fm.valueChanges.subscribe(v => {
      this.onChange(v);
    })
  }

  onChange = (_: any) => {}
  onTouched = () => {}

  writeValue(obj: any) {
    this.fm.setValue(obj);
  }
  registerOnChange(fn: any) {
    this.onChange = fn;
  }
  registerOnTouched(fn: any) {
    this.onTouched = fn;
  }

}

我可以为此组件(在AppComponent中)设置Validators.required

  ngOnInit() {
    this.formGroup = this.fb.group({
      control: ['', Validators.required],
      controlOne: ['', Validators.required]
    })

    this.formGroup.statusChanges
      .subscribe(console.log);
  }

,它会影响整个表单。 (您可以在控制台上看到:当ACompnent无效时无效)。

但是问题是,在无效的情况下,我不能强制AComponent看起来无效(红色输入)。 看起来内部formControl(在AComponent中)没有从AppComponent中获得Validators.required

enter image description here

问题是:我如何以一种优雅的方式将验证器设置为AComponent?

DEMO

3 个答案:

答案 0 :(得分:1)

答案 1 :(得分:1)

注意,当我们创建自定义表单控件时,Angular将ng-invalid ng-touched添加到我们的组件中。因此,通常我们使用.css

更改控件的外观
.ng-invalid.ng-touched
{
color:red;
}

问题是我们想在自定义表单控件中更改mat-input的外观。因此,我们需要知道什么时候控制无效。

this stackblitz中,您具有自定义的表单控件。

当您的自定义窗体控件无效时,知道密钥。为此,可以注入ngControl。使用inject避免循环依赖是必要的。所以,我们的构造函数就像

constructor(public injector: Injector) { }
  ngOnInit() {
    this.ngControl = this.injector.get(NgControl);
    this.fm.valueChanges.subscribe(v => {
      this.onChange(v);
    })
  }

好吧,我们知道自定义控件何时有效,被触摸,原始……

我们将定义一个.css之类的

.customError,.custom
{
  display:inline-block;
}
.customError .mat-form-field-empty.mat-form-field-label {
    color: red!important;
}
.customError .mat-form-field-underline {
    background-color: red!important;
}

并在组件中使用ViewEncapsulation.None。 ViewEncapsulation.None使得.css处于所有应用中。这是因为我们在.mat-form-field-empty.mat-form-field-label和mat-form-field-underline之前添加了“ .customError”类。否则,我们所有的垫子组件都看起来有错误。

@Component({
   selector: 'app-a',
   templateUrl: './a.component.html',
   styleUrls: [ './a.component.css' ],
   encapsulation:ViewEncapsulation.None,
   providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => AComponent),
    multi: true
   }]
})

此后,我们使用[ngClass]添加类

<div class="custom" 
    [ngClass]="{'customError':ngControl.invalid && ngControl.touched}" >

  <mat-form-field 
      [color]="ngControl.invalid && ngControl.touched?'warn':null" >
     <input matInput  placeholder="Some value" [formControl]="fm" (blur)="onTouched()">
  </mat-form-field>
</div>

看到我们在mat-form-field中使用属性[color]来使波纹下划线也变成红色,以及如何使用(模糊)将控件标记为触摸

答案 2 :(得分:0)

providers: [
    {
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => CustomInputComponent),
        multi: true
    },
    {
        provide: NG_VALIDATORS,
        useExisting: forwardRef(() => CustomInputComponent),
        multi: true
    }  
]

您也可以选择使用@Hostbinding设置ng-error类