包角材料输入的组件不显示错误样式 [英] Component for wrap angular material input does not show error styles

查看:67
本文介绍了包角材料输入的组件不显示错误样式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在组件中封装一个角材料的matInput以便在应用程序的其他地方重用它,因为我需要管理其内部状态,以将输入类型从文本更改为密码,反之亦然.

I want to enclose a matInput of angular material within a component to reuse it in other places of my application because I need to manage its internal state to change the input type from text to password and viceversa.

我通过实现ControlValueAccessor做到了这一点,但是没有显示验证错误的样式.

I managed to do it by implementing ControlValueAccessor but the styles of validation errors are not being displayed.

密码字段组件:

export class PasswordFieldComponent
  implements OnInit, ControlValueAccessor {

  @ViewChild(DefaultValueAccessor) private valueAccessor: DefaultValueAccessor;

  @Input() customClass: string;
  @Input() customPlaceholder: string;
  @Input() required = true;

  hide = true;

  constructor() { }

  ngOnInit() {
  }

  private propagateChange = (_: any) => { };

  private onChange(event) {
    this.propagateChange(event.target.value);
  }

  private onTouch() { }

  registerOnChange(fn: any): void {
    this.valueAccessor.registerOnChange(fn);
  }

  registerOnTouched(fn: any): void {
    this.valueAccessor.registerOnTouched(fn);
  }

  setDisabledState(isDisabled: boolean): void {
    this.valueAccessor.setDisabledState(isDisabled);
  }

  writeValue(value: any): void {
    this.valueAccessor.writeValue(value);
  }

}

密码字段模板:

<mat-form-field class="full-width {{ customClass }}">

  <input
    matInput
    ngDefaultControl
    placeholder="{{ customPlaceholder }}"
    [required]="required"
    [type]="hide ? 'password' : 'text'"
    (input)="onChange($event)">

  <button mat-icon-button matSuffix (click)="hide = !hide" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hide">
    <mat-icon>{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
  </button>

</mat-form-field>

推荐答案

我评论中的代码是最简单的自定义表单控件,内部具有材料输入".这个想法是创建自定义的ErrorStateMatcher,询问有关控件本身的信息.因此,内部材料输入显示错误不是在无效时显示错误,否则在我们的自定义控件无效时显示错误

The code from my comments is make the "most simple custom form control that has a material input inside". The idea is create custom ErrorStateMatcher that ask about the control itself. So, out inner material input show errors not when it was invalid else when our custom control was invalid

此ErrorStateMatcher需要了解我们的控件,因此我们将创建一个构造函数以注入该控件(我在构造函数中注入另一个对象错误"以使材料输入无效"

This ErrorStateMatcher need the know about our control, so we are going to create a constructor to inject this control (I inject in constructor another object "errors" to alow make "invalid" the material input)

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);
  }
}

.html就像

<mat-form-field>

    <input #input="ngModel" [ngModel]="value" (ngModelChange)="value=$event;onChange($event)"
    matInput
    [errorStateMatcher]="errorMatcher()"
    [placeholder]="placeholder"
    [type]="hide ? 'password' : 'text'"
    (blur)="onTouched()"
    >
    <button mat-icon-button matSuffix (click)="hide = !hide" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hide">
    <mat-icon>{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
  </button>
    <mat-error *ngIf="control?.errors?.required">
        Please enter a {{placeholder}}
    </mat-error>
    <mat-error *ngIf="errors?.errorMatch">
        Must match
    </mat-error>

</mat-form-field>

最重要的部分是这个

[errorStateMatcher]="errorMatcher()"

请参见使用[ngModel]和(ngModel),(模糊)将自定义formControl标记为已触摸".我添加了一个mat-error * ngIf ="errors?.errorMatch.这是一个@Input(),它获取Form的error值.这是因为如果两个字段"password"相同,我们将使FormGroup出现自定义错误.和"repeatpassword"不匹配.

See that use [ngModel] and (ngModel), (blur) mark the custom formControl "touched". I add a mat-error *ngIf="errors?.errorMatch. This is a @Input() that get the value of error of Form. This is because we are make a FormGroup that has an custom error if the two fields "password" and "repeatpassword" not match.

我们的自定义表单控件就像

Our custom form control is like

export class CustomSelectComponent implements AfterViewInit, ControlValueAccessor {

  control: FormControl
  onChange: any = () => { };
  onTouched: any = () => { };

  value: any;
  @Input() disabled: boolean;
  @Input() placeholder = '';
  @Input() errors:any=null;

  errorMatcher() {
    return new CustomFieldErrorMatcher(this.control,this.errors)
  }
  constructor(public injector: Injector) {
  }

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

查看如何在ngAfterViewInit中获取ngControl,如何errorMatcher()返回新的CustomFieldErrorMatcher以及如何传递"control"和"errors"的值.

See how get the ngControl in the ngAfterViewInit, how errorMatcher() return a new CustomFieldErrorMatcher and how pass the values of "control" and "errors".

好吧,我们的app.component就像

Well our app.component is like

  ngOnInit() {
    this.myForm = new FormGroup(
      {
        password: new FormControl("", Validators.required),
        repeatpassword: new FormControl("", Validators.required)
      },
      this.matchControls("password", "repeatpassword")
    );
  }

  matchControls(field1, field2) {
    return (group: FormGroup) => {
      const control1 = group.get(field1);
      const control2 = group.get(field2);
      return control1 && control2 &&
        control1.value && control2.value &&
        control1.value != control2.value
        ? { errorMatch: "must match" }: null;
    };
  }

app.component的.html是

The .html of the app.component is

<form [formGroup]="myForm" autocomplete="off">
    <app-custom-input placeholder="Password" formControlName="password" >
    </app-custom-input>
    <app-custom-input placeholder="Repeat password" formControlName="repeatpassword" [errors]="myForm.errors?.errorMatch?myForm.errors:null" >
    </app-custom-input>
</form>

stackblitz

在自定义组件上添加了此侦听器.您也可以将其模糊化".

added this listener on the custom component. You can also do it 'blur' event.

https://stackoverflow.com/a/59086644/12425844

@HostListener('focusout', ['$event.target'])
  onFocusout() {
    this.onTouched();
  }
And also calling onTouched when setting any value.

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

这篇关于包角材料输入的组件不显示错误样式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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