代码之家  ›  专栏  ›  技术社区  ›  danwellman

角度5,角度材质:日期选择器验证不起作用

  •  14
  • danwellman  · 技术社区  · 7 年前

    我正在使用最新的角度和最新的角度材料。我有一个日期选择器,我想添加一些验证。文件说 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>
    

    这在快乐路径上起作用,因此,当选择日期时,该日期将在中的预期属性中结束 myService .

    然而,验证并没有以我期望的方式工作;在这种情况下,如果我在字段中单击,然后在字段外单击,而不输入日期,则输入 [controlName].errors 对象未填充。这意味着以通常的方式显示错误消息(与不在同一页上的日期选择器的其他输入一起使用的方式)不起作用:

    <mat-error *ngIf="dob.errors && dob.errors.required">Your date of birth is required</mat-error>
    

    这个 *ngIf 从不为true,因为日期选择器似乎从未更新 dob.errors

    是这样吗?我错过什么了吗?

    我还尝试添加一个自定义指令,以验证使用日期选择器选择的日期是否表示用户已年满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;
      }
    }
    

    在这种情况下,我尝试使用类似的 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
    
    7 回复  |  直到 7 年前
        1
  •  8
  •   Manon Ingrassia    7 年前

    我在棱角材质形式中使用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>
    

    和类型脚本:

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

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

        2
  •  6
  •   danwellman    7 年前

    我没有使用 ErrorStateMatcher ,尽管这确实帮助我找到了解决方案。离开这里以供将来参考或帮助他人。

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

    以下是工作代码:

    我的表格。组成部分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>
    

    笔记 :上述代码位于两个嵌套 ngFor 定义值的循环 fieldset control . 在本例中 控制 映射到字符串 dob .

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

    我的表格。组成部分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);
    }
    
        3
  •  1
  •   Leonardo Neninger    7 年前

    您复制了#dob。在角度验证中可能会有不希望的行为。

    你有

    <input #dob='ngModel'
    

    <mat-datepicker #dob></mat-datepicker>
    

        4
  •  1
  •   Guvaliour    7 年前

    在查看页面中添加此内容:

          <mat-form-field>
         <input matInput [matDatepicker]="dp"   placeholder="Employement date" >
       <mat-datepicker-toggle matSuffix [for]="dp"></mat-datepicker-toggle>
       <mat-datepicker #dp></mat-datepicker>
        </mat-form-field>
    

    只需在模块中导入MatDatepickerModule、MatNativeDateModule

        5
  •  1
  •   Leonardo Neninger    7 年前

    您可以更改输入引用的名称,如下所示。。 请注意,输入元素#dobInput仅在mat error中引用。

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

    选择器由#dbo引用

    [matDatepicker]="dob"
    
    <mat-datepicker-toggle matSuffix [for]="dob"></mat-datepicker-toggle>
    
        6
  •  0
  •   Nour    7 年前

    您是否尝试将*ngIf设置为自定义验证器,如下所示:

     <mat-error *ngIf="dob.errors && dob.errors.validateAdult">Your date of birth 
     is less than 18 ?</mat-error>
    

    如果可行,您可以创建另一个验证器来模拟所需的本机验证行为。

    export class CustomRequireValidator implements Validator {
      constructor(
        @Attribute('app-validateRequired') public validateRequired: string
      ) { }
    
      validate(control: AbstractControl): { [key: string]: any } {
        let value = control.value;
        if (!value || value == null || value.toString().length == 0) {
            return requireValidator: {
          'requiredAge': 'This field is required',
        }
        }
    
        return null;
      }
    }
    

    然后使用之前的ngIf,如下所示:

     <mat-error *ngIf="dob.errors && dob.errors.requireValidator">Your date of 
    birth is less than 18 ?</mat-error>
    

    我没有测试它,但从逻辑上讲它应该可以工作。

        7
  •  -3
  •   A. STEFANI    7 年前

    看一看 this this . 请看一个基于javascript的工作示例 here .


    您还可以测试此(基于角度的)日期选择器:

    <div ng-app="example" ng-controller="AppCtrl">
      <md-datepicker ng-model="myDate" md-placeholder="Enter date"></md-datepicker>
    </div>
    

    JS公司:

    angular
      .module('example', ['ngMaterial'])
      .config(function($mdDateLocaleProvider) {
        $mdDateLocaleProvider.formatDate = function(date) {
          return moment(date).format('DD/MM/YYYY');
        };
    
        $mdDateLocaleProvider.parseDate = function(dateString) {
          var m = moment(dateString, 'DD/MM/YYYY', true);
          return m.isValid() ? m.toDate() : new Date(NaN);
        };
      })
      .controller('AppCtrl', function($scope) {
        $scope.myDate = new Date();
      });