Javascript Angular 5,Angular Material:Datepicker 验证不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48283415/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Angular 5, Angular Material: Datepicker validation not working
提问by danwellman
I'm using the latest Angular and latest Angular Material. I've got a datepicker and I want to add some validation. Documents say that the requiredattribute should work out of the box, but it doesn't seem to handle errors in the same way that other form elements do.
我正在使用最新的 Angular 和最新的 Angular Material。我有一个日期选择器,我想添加一些验证。文档说该required属性应该是开箱即用的,但它似乎不像其他表单元素那样处理错误。
Here is my mark-up:
这是我的标记:
<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>
This works on the happy-path, so when a date is picked, the date ends up in the expected property in myService.
这在快乐路径上工作,所以当挑选日期时,日期最终在预期的财产中myService。
The validation does not work in the way that I would expect however; in this case, if I click into the field and then out of the field without entering a date, then the input doesget red styling, but the usual [controlName].errorsobject does not get populated. This means that showing an error message in the usual way (the way that works with other inputs that are not date pickers on the same page) does not work:
然而,验证并没有像我期望的那样工作;在这种情况下,如果我单击进入该字段然后离开该字段而不输入日期,则输入确实会获得红色样式,但[controlName].errors不会填充通常的对象。这意味着以通常的方式显示错误消息(与同一页面上不是日期选择器的其他输入一起工作的方式)不起作用:
<mat-error *ngIf="dob.errors && dob.errors.required">Your date of birth is required</mat-error>
The *ngIfis never true because the datepicker never seems to update dob.errors, so the error message is never shown, even when the input is styled as invalid.
在*ngIf因为日期选择器似乎从来没有更新是不正确的dob.errors,这样就不会显示错误消息,即使输入的样式为无效。
Is this right? Have I missed something?
这是正确的吗?我错过了什么吗?
I've also tried adding a custom directive to validate that the date selected with the datepicker indicates that the user is over 18:
我还尝试添加自定义指令来验证使用日期选择器选择的日期是否表明用户已超过 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;
}
}
In this case I'm trying to use a similar matError(except linked to dob.errors.validateAdultinstead) to show the error when appropriate.
在这种情况下,我试图在适当的时候使用类似的matError(除了链接到dob.errors.validateAdult)来显示错误。
The interesting thing with this is that if I pick a date less than 18 years ago, the whole input, label, etc, gets the default red error styling, so something is happening, but I still don't see my error message.
有趣的是,如果我选择一个不到 18 年前的日期,整个输入、标签等都会获得默认的红色错误样式,所以发生了一些事情,但我仍然看不到我的错误消息。
Any suggestions would be much appreciated!
我们欢迎所有的建议!
Exact versions:
确切版本:
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
采纳答案by danwellman
I managed to get this working without using the ErrorStateMatcher, although that did help me reach the solution. Leaving here for future reference or to help others.
我设法在不使用 的情况下完成了这项工作ErrorStateMatcher,尽管这确实帮助我找到了解决方案。离开这里以供将来参考或帮助他人。
I converted my form to a reactive form instead of a template-driven form, and I changed the custom validator directive to a simpler validator (non-directive-based).
我将表单转换为反应式表单而不是模板驱动的表单,并将自定义验证器指令更改为更简单的验证器(非基于指令)。
Here is the working code:
这是工作代码:
my-form.component.html:
我的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>
note: The above code is inside a couple of nested ngForloops which define the value of fieldsetand control. In this example controlmaps to the string dob.
注意:上面的代码位于几个ngFor定义fieldsetand值的嵌套循环中control。在这个例子中control映射到字符串dob。
over-eighteen.validator.ts:
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;
};
}
my-form.component.ts:
我的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);
}
回答by Manon Ingrassia
I use ErrorStateMatcher in my Angular Material Forms, it works perfectly.
我在我的 Angular Material Forms 中使用 ErrorStateMatcher,它工作得很好。
You should have a code that looks like that:
你应该有一个看起来像这样的代码:
<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>
And typescript:
和打字稿:
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();
}
You can see here more about it: https://material.angular.io/components/input/overview
你可以在这里看到更多关于它的信息:https: //material.angular.io/components/input/overview
回答by Guvaliour
Add this in your view page:
在您的视图页面中添加:
<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>
Just import MatDatepickerModule,MatNativeDateModule in your module
只需在您的模块中导入 MatDatepickerModule,MatNativeDateModule
回答by Leonardo Neninger
You can change name of the input reference like below.. Notice that input element #dobInput is referenced only in mat-error.
您可以像下面那样更改输入引用的名称。请注意,输入元素 #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>
The picker is referenced by #dbo
选择器由#dbo 引用
[matDatepicker]="dob"
<mat-datepicker-toggle matSuffix [for]="dob"></mat-datepicker-toggle>
回答by Leonardo Neninger
You have the #dob duplicated. That can have a undesired behavior in angular validation.
您复制了#dob。这可能会在角度验证中产生不良行为。
You have
你有
<input #dob='ngModel'
and
和
<mat-datepicker #dob></mat-datepicker>
Please fix the naming convention and see what happen.
请修正命名约定,看看会发生什么。
回答by Nour
Did you try to set the *ngIf to your custom validator like below:
您是否尝试将 *ngIf 设置为您的自定义验证器,如下所示:
<mat-error *ngIf="dob.errors && dob.errors.validateAdult">Your date of birth
is less than 18 ?</mat-error>
If that works, you can create another validator to simulate the required native validation behavior.
如果可行,您可以创建另一个验证器来模拟所需的本机验证行为。
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;
}
}
And then use the previous ngIf as below:
然后使用之前的 ngIf 如下:
<mat-error *ngIf="dob.errors && dob.errors.requireValidator">Your date of
birth is less than 18 ?</mat-error>
I did not test it but logically it should work.
我没有测试它,但从逻辑上讲它应该可以工作。
回答by A STEFANI
Take a look on this, and this. And please see a working javascript based example here.
看看这个,还有这个。请在此处查看一个基于 javascript 的工作示例。
You may also test this (angular based) datepicker:
您还可以测试这个(基于角度的)日期选择器:
HTML:
HTML:
<div ng-app="example" ng-controller="AppCtrl">
<md-datepicker ng-model="myDate" md-placeholder="Enter date"></md-datepicker>
</div>
JS:
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();
});

