角材料中带有错误验证的 ControlValueAccessor [英] ControlValueAccessor with Error Validation in Angular Material

查看:20
本文介绍了角材料中带有错误验证的 ControlValueAccessor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在自定义材料输入文本框中使用 ControlValueAccessor 应用错误验证样式.自从应用这个自定义组件以来,所有带有 formControlName/FormBuilders 的红色边框验证状态都不会显示,例如 required、minlength 等.它在 Angular Material 文本框上原生(开箱即用)工作,直到应用了自定义控件.

目标是让自定义文本框与表单验证一起工作.这与 matInput 文本框自然显示.

更新:已发布答案;但是不确定它是否最有效,试图让 Saloo 的答案也能正常工作(如果有人可以发布 stackbliz,那就太好了),对任何更有效的选择持开放态度

打字稿:

import { Component, OnInit, Input, ViewChild, EventEmitter, Output, forwardRef } from '@angular/core';从@angular/forms"导入 { ControlValueAccessor, NG_VALUE_ACCESSOR };@成分({选择器:应用程序输入文本框",templateUrl: './input-textbox.component.html',styleUrls: ['./input-textbox.component.scss'],供应商: [{提供:NG_VALUE_ACCESSOR,useExisting: forwardRef(() => InputTextboxComponent),多:真}]})导出类 InputTextboxComponent 实现 OnInit、ControlValueAccessor {@Input() MaxLength: 字符串;@Input() 值:字符串;@Input() 类型:字符串;@Input() 标签:字符串;@Input() 占位符:字符串;@Output() saveValue = new EventEmitter();@Output() onStateChange = new EventEmitter();禁用:布尔值;构造函数(){}ngOnInit() {}saveValueAction(e) {this.saveValue.emit(e.target.value);}onChange(e) {this.Value = e;}onTouched() {this.onStateChange.emit();}写值(值:任何){this.Value = 值?价值 : '';}registerOnChange(fn: any) { this.onChange = fn;}registerOnTouched(fn: any) { this.onTouched = fn;}setDisabledState(isDisabled) { this.disabled = isDisabled;}}

HTML:

<mat-form-field appearance="outline"><mat-label>{{Label}}</mat-label><输入垫输入[attr.maxlength] = "MaxLength"[值]="值?值:''"[占位符]="PlaceHolder ? PlaceHolder : ''"[type]="type ? type: 'text'"(输入)="onChange($event.target.value)"></mat-form-field>

尝试将此答案与 Angular Material 文本框的自然错误样式结合起来,在 Angular 中使用 ControlValueAccessor 继承验证

解决方案

这将创建来自 Angular Material 的错误验证

打字稿:

import { Component, OnInit, Input, EventEmitter, Output, forwardRef, Injector } from '@angular/core';导入 { ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl, NgForm, FormGroupDirective, NgControl } from '@angular/forms';从'@angular/material'导入{ErrorStateMatcher};导出类 CustomFieldErrorMatcher 实现 ErrorStateMatcher {构造函数(私有自定义控件:FormControl,私有错误:任何){}isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {返回 this.customControl &&this.customControl.touched &&(this.customControl.invalid || this.errors);}}@成分({选择器:应用程序输入文本框",templateUrl: './input-textbox.component.html',styleUrls: ['./input-textbox.component.scss'],供应商: [{提供:NG_VALUE_ACCESSOR,useExisting: forwardRef(() => InputTextboxComponent),多:真}]})导出类 InputTextboxComponent 实现 OnInit、ControlValueAccessor {@Input() MaxLength: 字符串;@Input() 焦点输入:布尔值;@Input() 宽度:字符串;@Input() 值:字符串;@Input() 类型:字符串;@Input() 标签:字符串;@Input() 提示:字符串;@Input() 占位符:字符串;@Output() saveValue = new EventEmitter();@Output() onStateChange = new EventEmitter();@Input() 错误:any = null;禁用:布尔值;控件:表单控件;构造函数(公共注入器:注入器){}ngOnInit(){}ngAfterViewInit(): 无效 {const ngControl: NgControl = this.injector.get(NgControl, null);如果(ngControl){setTimeout(() => {this.control = ngControl.control 作为 FormControl;})}}saveValueAction(e) {this.saveValue.emit(e.target.value);}//控制值访问器init写值(值:任何){this.Value = 值?价值 : '';}onChange(e) {this.Value = e;}onTouched() {this.onStateChange.emit();}registerOnChange(fn: any) { this.onChange = fn;}registerOnTouched(fn: any) { this.onTouched = fn;}setDisabledState(isDisabled) { this.disabled = isDisabled;}errorMatcher() {返回新的 CustomFieldErrorMatcher(this.control,this.errors)}只读 errorStateMatcher: ErrorStateMatcher = {isErrorState: (ctrl: FormControl) =>(ctrl && ctrl.invalid)};}

HTML

<mat-form-field><mat-label>{{Label}}</mat-label><输入垫输入[attr.maxlength] = "MaxLength"[值]="值?值:''"[占位符]="PlaceHolder ? PlaceHolder : ''"[type]="type ? type: 'text'"[ngModel]="值"[errorStateMatcher]="errorMatcher()"(输入)="onChange($event.target.value)"(模糊)="onTouched()"(change)="saveValueAction($event)"(ngModelChange)="值=$event;onChange($event)"><mat-h​​int>{{Hint}}</mat-h​​int></mat-form-field>

I am trying to apply Error Validation style with ControlValueAccessor in custom Material Input Textbox. Ever since applying this custom component, all the red border validation status with formControlName/FormBuilders do not show, for required, minlength, etc. It worked natively (out of the box) with Angular Material textbox, until the custom control was applied.

Goal is to have custom textbox working with Form validation. This showed naturally with matInput textbox.

Update: Posted answer; however not sure if its most efficient one, trying to get Saloo answer working also (if someone can post stackbliz, would be great), open to any more efficient options

Typescript:

import { Component, OnInit, Input, ViewChild, EventEmitter, Output, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-input-textbox',
  templateUrl: './input-textbox.component.html',
  styleUrls: ['./input-textbox.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => InputTextboxComponent),
      multi: true
    }
  ]
})

export class InputTextboxComponent implements OnInit, ControlValueAccessor {
  @Input() MaxLength: string;
  @Input() Value: string;
  @Input() type: string;
  @Input() Label: string;
  @Input() PlaceHolder: string;
  @Output() saveValue = new EventEmitter();
  @Output() onStateChange = new EventEmitter();

  disabled: boolean;

  constructor() { }

  ngOnInit() {
  }

  saveValueAction(e) {
    this.saveValue.emit(e.target.value);
  }

  onChange(e) {
    this.Value = e;
  }

  onTouched() {
    this.onStateChange.emit();
  }

  writeValue(value: any) {
    this.Value = value ? value : '';
  }

  registerOnChange(fn: any) { this.onChange = fn; }

  registerOnTouched(fn: any) { this.onTouched = fn; }

  setDisabledState(isDisabled) { this.disabled = isDisabled; }
}

HTML:

<div class="input-wrap">
    <mat-form-field appearance="outline">
        <mat-label>{{Label}}</mat-label>   
        <input matInput 
            [attr.maxlength] = "MaxLength"
            [value]="Value ? Value : ''"
            [placeholder]="PlaceHolder ? PlaceHolder : ''"
            [type]="type ? type: 'text'"
            (input)="onChange($event.target.value)"
        >
    </mat-form-field>
</div>

Trying to incorporate this answer with the natural error styling from Angular Material textbox, Inheriting validation using ControlValueAccessor in Angular

解决方案

This will create error validation from Angular Material

Typescript:

import { Component, OnInit, Input, EventEmitter, Output, forwardRef, Injector } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl, NgForm, FormGroupDirective, NgControl } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material';

export class CustomFieldErrorMatcher implements ErrorStateMatcher {
  constructor(private customControl: FormControl,private errors:any) { }

  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    return this.customControl && this.customControl.touched &&(this.customControl.invalid || this.errors);
  }
}

@Component({
  selector: 'app-input-textbox',
  templateUrl: './input-textbox.component.html',
  styleUrls: ['./input-textbox.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => InputTextboxComponent),
      multi: true
    }
  ]
})

export class InputTextboxComponent implements OnInit, ControlValueAccessor {
  @Input() MaxLength: string;
  @Input() FocusIn: boolean;
  @Input() Width: string;
  @Input() Value: string;
  @Input() type: string;
  @Input() Label: string;
  @Input() Hint: string;
  @Input() PlaceHolder: string;
  @Output() saveValue = new EventEmitter();
  @Output() onStateChange = new EventEmitter();
  @Input() errors: any = null;
  disabled: boolean;
  control: FormControl;

  constructor(public injector: Injector) {}

  ngOnInit(){}

  ngAfterViewInit(): void {
    const ngControl: NgControl = this.injector.get(NgControl, null);
    if (ngControl) {
      setTimeout(() => {
        this.control = ngControl.control as FormControl;
      })
    }
  }

  saveValueAction(e) {
    this.saveValue.emit(e.target.value);
  }

  //control value accessor init
  writeValue(value: any) {
    this.Value = value ? value : '';
  }

  onChange(e) {
    this.Value = e;
  }

  onTouched() {
    this.onStateChange.emit();
  }

  registerOnChange(fn: any) { this.onChange = fn; }

  registerOnTouched(fn: any) { this.onTouched = fn; }

  setDisabledState(isDisabled) { this.disabled = isDisabled; }

  errorMatcher() {
    return new CustomFieldErrorMatcher(this.control,this.errors)
  }

  readonly errorStateMatcher: ErrorStateMatcher = {
    isErrorState: (ctrl: FormControl) => (ctrl && ctrl.invalid)
  };

}

HTML

<div class="input-wrap">
    <mat-form-field>
        <mat-label>{{Label}}</mat-label>   
        <input 
            matInput 
            [attr.maxlength] = "MaxLength"
            [value]="Value ? Value : ''"
            [placeholder]="PlaceHolder ? PlaceHolder : ''"
            [type]="type ? type: 'text'"
            [ngModel]="Value" 
            [errorStateMatcher]="errorMatcher()"

            (input)="onChange($event.target.value)"
            (blur)="onTouched()"
            (change)="saveValueAction($event)"
            (ngModelChange)="Value=$event;onChange($event)"
        >
        <mat-hint>{{Hint}}</mat-hint>
    </mat-form-field>
</div>

这篇关于角材料中带有错误验证的 ControlValueAccessor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆