使用MAT错误显示自定义验证器错误[英] Display custom validator error with mat-error

本文是小编为大家收集整理的关于使用MAT错误显示自定义验证器错误的处理方法,想解了使用MAT错误显示自定义验证器错误的问题怎么解决?使用MAT错误显示自定义验证器错误问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我来找你谈论角度的物质问题.事实上,我认为这是一个问题,但我更喜欢先寻找一个牵引权.

我的问题的第一件事是上下文,我尝试做一个包含两个输入的简单形式:密码及其确认.

user-form..component.ts

this.newUserForm = this.fb.group({
  type: ['', Validators.required],
  firstname: ['', Validators.required],
  lastname: ['', Validators.required],
  login: ['', Validators.required],
  matchingPasswordsForm: this.fb.group(
    {
      password1: ['', Validators.required],
      password2: ['', Validators.required],
    },
    {
      validator: MatchingPasswordValidator.validate,
    },
  ),
  mail: ['', [Validators.required, Validators.pattern(EMAIL_PATTERN)]],
  cbaNumber: [
    '411000000',
    [Validators.required, Validators.pattern(CBANUMBER_PATTERN)],
  ],
  phone: ['', [Validators.required, Validators.pattern(PHONE_PATTERN)]],
}

我的兴趣是关于匹配的匹配型Worm FormGroup.您可以看到它的验证器.

这里验证器:

matching-password.validator.ts

export class MatchingPasswordValidator {
    constructor() {}

    static validate(c: FormGroup): ValidationErrors | null {
        if (c.get('password2').value !== c.get('password1').value) {
            return { matchingPassword: true};
        }
        return null;
    }
}

和html.

user-form..component.html

<div class="row" formGroupName="matchingPasswordsForm">
    <mat-form-field class="col-md-6 col-sm-12">
        <input matInput placeholder="Mot de passe:" formControlName="password1">
        <mat-error ngxErrors="matchingPasswordsForm.password1">
            <p ngxError="required" [when]="['dirty', 'touched']">{{requiredMessage}}</p>
        </mat-error>
    </mat-form-field>

    <mat-form-field class="col-md-6 col-sm-12">
        <input matInput placeholder="Confirmez" formControlName="password2">
        <mat-error ngxErrors="matchingPasswordsForm.password2">
            <p ngxError="required" [when]="['dirty', 'touched']">{{requiredMessage}}</p>
        </mat-error>
        <!--                 -->
        <!-- problem is here -->
        <!--                 -->
        <mat-error ngxErrors="matchingPasswordsForm" class="mat-error">
            <p ngxError="matchingPassword" [when]="['dirty', 'touched']">{{passwordMatchErrorMessage}}</p>
        </mat-error>
        <!-- ^^^^^^^^^^^^^^^^ -->
        <!-- /problem is here -->
        <!--                  -->
    </mat-form-field>
</div>

我已经通过评论包围了有趣的代码.

现在,一些解释:使用标签,当触摸密码2时,显示我的错误:

password2刚触摸

但是,当我编写错误的密码时,不再显示错误:

错误的password2

首先我认为我误解了自定义验证器利用率.但是当我用整体替换完美的工作时!

通过提示更换错误

<mat-hint ngxErrors="matchinghPasswordsForm">
    <p ngxError="matchingPassword" [when]="['dirty', 'touched']">{{passwordMatchErrorMessage}}</p>
</mat-hint>

有mat-h​​int tag

我希望我很清楚,在发布物料设计github问题之前,我真的想要你的观点.

如果我误导了一些东西,请在我错过的东西上点燃我的火.

最后一件事,我的测试是用ngxerrors和* ngif完成的.更易读我的代码示例仅使用ngxerrors.

提前感谢您的时间.

推荐答案

alex 是正确的.您必须使用ErrorStateMatcher.我不得不做很多研究来解决这个问题,而且没有一个源给了我整个答案的来源.我不得不将我从多个来源学到的信息汇集在一起​​,以使自己解决问题的解决方案.希望以下示例将使您从我经历的头痛中拯救出来.

形式

这里是使用用户登记页面的角度材料元素的形式的示例.

<form [formGroup]="userRegistrationForm" novalidate>

    <mat-form-field>
        <input matInput placeholder="Full name" type="text" formControlName="fullName">
        <mat-error>
            {{errors.fullName}}
        </mat-error>
    </mat-form-field>

    <div formGroupName="emailGroup">
        <mat-form-field>
            <input matInput placeholder="Email address" type="email" formControlName="email">
            <mat-error>
                {{errors.email}}
            </mat-error>
        </mat-form-field>

        <mat-form-field>    
            <input matInput placeholder="Confirm email address" type="email" formControlName="confirmEmail" [errorStateMatcher]="confirmValidParentMatcher">
            <mat-error>
                {{errors.confirmEmail}}
            </mat-error>
        </mat-form-field>
    </div>

    <div formGroupName="passwordGroup">
        <mat-form-field>
            <input matInput placeholder="Password" type="password" formControlName="password">
            <mat-error>
                {{errors.password}}
            </mat-error>
        </mat-form-field>
    
        <mat-form-field>
            <input matInput placeholder="Confirm password" type="password" formControlName="confirmPassword" [errorStateMatcher]="confirmValidParentMatcher">
            <mat-error>
                {{errors.confirmPassword}}
            </mat-error>
        </mat-form-field>
    </div>

    <button mat-raised-button [disabled]="userRegistrationForm.invalid" (click)="register()">Register</button>

</form>

可以看出,我使用来自角度材料的<mat-form-field>,<input matInput>和<mat-error>标签.我的第一个想法是添加*ngIf指令来控制<mat-error>部分出现,但这没有效果!可见性实际上由<mat-form-field>的有效性(和"触摸"状态)控制,并且没有提供的验证器以在HTML或Angular中的另一个表单字段测试平等.这就是确认字段上的errorStateMatcher指令的位置.

指令内置于角度材料,并提供使用自定义方法来确定<mat-form-field>形式控件的有效性的能力,并允许访问父母的有效状态.要开始了解我们如何为此用例使用errorstateMatcher,请首先查看组件类.

组件类

这是一个角度组成级,可以使用formbuilder为表单设置验证.

export class App {
    userRegistrationForm: FormGroup;

    confirmValidParentMatcher = new ConfirmValidParentMatcher();

    errors = errorMessages;

    constructor(
        private formBuilder: FormBuilder
    ) {
        this.createForm();
    }

    createForm() {
        this.userRegistrationForm = this.formBuilder.group({
            fullName: ['', [
                Validators.required,
                Validators.minLength(1),
                Validators.maxLength(128)
            ]],
            emailGroup: this.formBuilder.group({
                email: ['', [
                    Validators.required,
                    Validators.email
                ]],
                confirmEmail: ['', Validators.required]
            }, { validator: CustomValidators.childrenEqual}),
            passwordGroup: this.formBuilder.group({
                password: ['', [
                    Validators.required,
                    Validators.pattern(regExps.password)
                ]],
                confirmPassword: ['', Validators.required]
            }, { validator: CustomValidators.childrenEqual})
        });
    }

    register(): void {
        // API call to register your user
    }
}

类为用户注册表单设置FormBuilder.请注意,该类中有两个FormGroup S,用于确认电子邮件地址,以及用于确认密码的一个FormGroup S.各个字段使用适当的验证器函数,但两者都在组级别使用自定义验证器,该级别检查,以确保每个组中的字段相互等于彼此,并且如果它们不是,则返回验证错误.

为组的自定义验证器和errorstateMatcher指令的组合是为我们提供了适当显示确认字段验证错误所需的完整功能.让我们来看看自定义验证模块,将其全部带到一起.

自定义验证模块

我选择将自定义验证功能分解为自己的模块,以便可以轻松重复使用.我还选择将其他与我的表单验证相关的东西,即定期表达式和错误消息,出于同样的原因.提前思考一点,很可能您将允许用户在用户更新表单中更改其电子邮件地址和密码,右图?这是整个模块的代码.

import { FormGroup, FormControl, FormGroupDirective, NgForm, ValidatorFn } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material';

/**
 * Custom validator functions for reactive form validation
 */
export class CustomValidators {
    /**
     * Validates that child controls in the form group are equal
     */
    static childrenEqual: ValidatorFn = (formGroup: FormGroup) => {
        const [firstControlName, ...otherControlNames] = Object.keys(formGroup.controls || {});
        const isValid = otherControlNames.every(controlName => formGroup.get(controlName).value === formGroup.get(firstControlName).value);
        return isValid ? null : { childrenNotEqual: true };
    }
}

/**
 * Custom ErrorStateMatcher which returns true (error exists) when the parent form group is invalid and the control has been touched
 */
export class ConfirmValidParentMatcher implements ErrorStateMatcher {
    isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
        return control.parent.invalid && control.touched;
    }
}

/**
 * Collection of reusable RegExps
 */
export const regExps: { [key: string]: RegExp } = {
    password: /^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{7,15}$/
};

/**
 * Collection of reusable error messages
 */
export const errorMessages: { [key: string]: string } = {
    fullName: 'Full name must be between 1 and 128 characters',
    email: 'Email must be a valid email address (username@domain)',
    confirmEmail: 'Email addresses must match',
    password: 'Password must be between 7 and 15 characters, and contain at least one number and special character',
    confirmPassword: 'Passwords must match'
};

首先让我们来看看组的自定义验证器函数CustomValidators.childrenEqual().由于我来自面向对象的编程背景,因此我选择使此功能成为静态类方法,但您可以轻松地使其成为独立的功能.该函数必须是ValidatorFn(或拨备的文字签名),并采用类型AbstractControl或任何导数类型的单个参数.我选择制作它FormGroup,因为这是它的用例.

函数的代码遍历FormGroup中的所有控件,并确保它们的值都与第一控件的所有值相等.如果他们这样做,它会返回null(表示没有错误),否则返回a childrenNotEqual错误.

所以现在我们在组时在组上的状态无效状态,但是当字段不相等时,我们仍然需要使用该状态来控制何时显示我们的错误消息.我们的ErrorStateMatcher ConfirmValidParentMatcher,是我们可以这样做的. ErrorStateMatcher指令要求您指向一个类的实例,它在角度材料中实现所提供的错误代码atcher类.这是这里使用的签名. ErrorStateMatcher需要实现isErrorState方法,签名在代码中显示.它返回true或false; true表示存在错误,这使得输入元素的状态无效.

此方法中的单行代码非常简单;如果父控件(我们的formgroup)无效,则返回true(存在错误),但仅当触摸该字段时.这与<mat-error>的默认行为对齐,我们正在使用表单上的其余字段.

要将其携带在一起,我们现在拥有一个具有自定义验证器的FormGroup,当我们的字段不等于时,返回错误,以及当组无效时显示的<mat-error>.要查看此功能,这里是一个工作 plunker ,其中提到的代码.

也,我博客这个解决方案这里.

其他推荐答案

如何创建自定义验证:

如果组件的内部属性"Isvalid"是假的,则会错误地设置错误,并显示一条消息.

html:

<input matInput
[formControl]="inputControl"
[placeholder]="placeholder"
[readonly]="readonly"
[errorStateMatcher]="matcher">

<mat-error *ngIf="!isValid">
Input not valid.
</mat-error>

ts:

isValid = true;

changeValitationStatus() {
this.matcher = new InputErrorStateMatcher(!this.isValid);
}

matcher = new InputErrorStateMatcher(!this.isValid);



class InputErrorStateMatcher implements ErrorStateMatcher {
    constructor(private errorstate: boolean) {}
    isErrorState(control: FormControl|null, form: FormGroupDirective|NgForm|null):boolean {
    return this.errorstate;
  }
}

,以这种方式,您只使用FormControl使用验证.

其他推荐答案

痴迷Programmer 答案对我来说是正确的,但我不得不改变childrenEqual功能Angular 6和strictNullChecks(该角度队推荐的选项)为此:

static childrenEqual: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
        const f = control as FormGroup;

        const [firstControlName, ...otherControlNames] = Object.keys(f.controls || {});

        if(f.get(firstControlName) == null) {
            return null;
        }

        otherControlNames.forEach(controlName => {
            if(f.get(controlName) == null) {
                return null;
            }
        })

        const isValid = otherControlNames.every(controlName => f.get(controlName)!.value === f.get(firstControlName)!.value);
        return isValid ? null : { childrenNotEqual: true };
    }

本文地址:https://www.itbaoku.cn/post/1793767.html