Angular 5,Angular Material:Datepicker验证不起作用

dan*_*man 9 javascript validation typescript angular-material2 angular

我正在使用最新的Angular和最新的Angular Material.我有一个datepicker,我想添加一些验证.文档说该required属性应该开箱即用,但它似乎不像其他表单元素那样处理错误.

这是我的加价:

<mat-form-field class="full-width">
    <input matInput [matDatepicker]="dob" placeholder="Date of birth" [(ngModel)]="myService.request.dob" #dob="ngModel" required app-validateAdult>
    <mat-datepicker-toggle matSuffix [for]="dob"></mat-datepicker-toggle>
    <mat-datepicker #dob></mat-datepicker>
    <mat-error *ngIf="dob.errors && dob.errors.required">Your date of birth is required</mat-error>
</mat-form-field>
Run Code Online (Sandbox Code Playgroud)

这适用于happy-path,因此当选择日期时,日期最终会出现在期望的属性中myService.

然而,验证并不像我期望的那样有效; 在这种情况下,如果我在没有输入日期的情况下单击该字段然后退出该字段,则输入获得红色样式,但通常的[controlName].errors对象不会被填充.这意味着以通常的方式显示错误消息(与同一页面上不是日期选择器的其他输入一起使用的方式)不起作用:

<mat-error *ngIf="dob.errors && dob.errors.required">Your date of birth is required</mat-error>
Run Code Online (Sandbox Code Playgroud)

*ngIf因为日期选择器似乎从来没有更新是不正确的dob.errors,这样就不会显示错误消息,即使输入的样式为无效.

这是正确的吗?我错过了什么吗?

我还尝试添加一个自定义指令来验证使用datepicker选择的日期表明用户已超过18:

export class AdultValidator implements Validator {
  constructor(
    @Attribute('app-validateAdult') public validateAdult: string
  ) { }

  validate(control: AbstractControl): { [key: string]: any } {
    const dob = control.value;
    const today = moment().startOf('day');
    const delta = today.diff(dob, 'years', false);

    if (delta <= 18) {
      return {
        validateAdult: {
          'requiredAge': '18+',
          'currentAge': delta
        }
      };
    }

    return null;
  }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我正在尝试使用类似的matError(除了链接dob.errors.validateAdult而不是)在适当时显示错误.

有趣的是,如果我选择一个不到18年前的日期,整个输入,标签等,将获得默认的红色错误样式,所以发生了一些事情,但我仍然没有看到我的错误消息.

我们欢迎所有的建议!

确切版本:

Angular CLI: 1.6.3
Node: 6.11.0
OS: win32 x64
Angular: 5.1.3
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

@angular/cdk: 5.0.4
@angular/cli: 1.6.3
@angular/flex-layout: 2.0.0-beta.12
@angular/material-moment-adapter: 5.0.4
@angular/material: 5.0.4
@angular-devkit/build-optimizer: 0.0.36
@angular-devkit/core: 0.0.22
@angular-devkit/schematics: 0.0.42
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.3
@schematics/angular: 0.1.11
@schematics/schematics: 0.0.11
typescript: 2.4.2
webpack: 3.10.0
Run Code Online (Sandbox Code Playgroud)

dan*_*man 6

我设法在不使用 的情况下完成了这项工作ErrorStateMatcher,尽管这确实帮助我找到了解决方案。离开这里以供将来参考或帮助他人。

我将表单转换为反应式表单而不是模板驱动的表单,并将自定义验证器指令更改为更简单的验证器(非基于指令)。

这是工作代码:

我的form.component.html:

<div class="container" fxlayoutgap="16px" fxlayout fxlayout.xs="column" fxlayout.sm="column" *ngIf="fieldset.controls[control].type === 'datepicker'">
  <mat-form-field class="full-width" fxflex>
    <input matInput 
           [formControlName]="control"
           [matDatepicker]="dob"
           [placeholder]="fieldset.controls[control].label" 
           [max]="fieldset.controls[control].validation.max">
    <mat-datepicker-toggle matSuffix [for]="dob"></mat-datepicker-toggle>
    <mat-datepicker #dob></mat-datepicker>
    <mat-error *ngIf="myForm.get(control).hasError('required')">
      {{fieldset.controls[control].validationMessages.required}}</mat-error>
    <mat-error *ngIf="myForm.get(control).hasError('underEighteen')">
      {{fieldset.controls[control].validationMessages.underEighteen}}
    </mat-error>
  </mat-form-field>
</div>
Run Code Online (Sandbox Code Playgroud)

注意:上面的代码位于几个ngFor定义fieldsetand值的嵌套循环中control。在这个例子中control映射到字符串dob

over-teen.validator.ts:

import { ValidatorFn, AbstractControl } from '@angular/forms';
import * as moment from 'moment';

export function overEighteen(): ValidatorFn {
  return (control: AbstractControl): { [key: string]: any } => {
    const dob = control.value;
    const today = moment().startOf('day');
    const delta = today.diff(dob, 'years', false);

    if (delta <= 18) {
      return {
        underEighteen: {
          'requiredAge': '18+',
          'currentAge': delta
        }
      };
    }

    return null;
  };
}
Run Code Online (Sandbox Code Playgroud)

我的form.component.ts:

buildForm(): void {
  const formObject = {};

  this.myService.request.fieldsets.forEach((controlsGroup, index) => {

    this.fieldsets.push({
      controlNames: Object.keys(controlsGroup.controls)
    });

    for (const control in controlsGroup.controls) {
      if (controlsGroup.controls.hasOwnProperty(control)) {
        const controlData = controlsGroup.controls[control];
        const controlAttributes = [controlData.value];
        const validators = [];

        if (controlData.validation) {
          for (const validator in controlData.validation) {
            if (controlData.validation.hasOwnProperty(validator)) {
              if (validator === 'overEighteenValidator') {
                validators.push(this.overEighteenValidator);
              } else {
                validators.push(Validators[validator]);
              }
            }
          }
          controlAttributes.push(Validators.compose(validators));
        }

        formObject[control] = controlAttributes;
      }
    }
  });

  this.myForm = this.fb.group(formObject);
}
Run Code Online (Sandbox Code Playgroud)


Man*_*sia 5

我在Angular Material Forms中使用ErrorStateMatcher,它运行完美。

您应该具有如下代码:

<mat-form-field class="full-width">
    <input matInput [matDatepicker]="dob" placeholder="Date of birth" formControlName="dob" required app-validateAdult>
    <mat-datepicker-toggle matSuffix [for]="dob"></mat-datepicker-toggle>
    <mat-datepicker #dob></mat-datepicker>
    <mat-error *ngIf="dob.hasError('required')">Your date of birth is required</mat-error>
</mat-form-field>
Run Code Online (Sandbox Code Playgroud)

和打字稿:

import { ErrorStateMatcher } from '@angular/material/core';

export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(
    control: FormControl | null,
    form: FormGroupDirective | NgForm | null
  ): boolean {
    const isSubmitted = form && form.submitted;
    return !!(
      control &&
      control.invalid &&
      (control.dirty || control.touched || isSubmitted)
    );
  }
}


export class AdultValidator implements Validator {
  dob = new FormControl('', [
    Validators.required
  ]);

  matcher = new MyErrorStateMatcher();
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处查看有关它的更多信息:https : //material.angular.io/components/input/overview