Javascript 角度5,角度材质:日期选择器验证不工作
我使用的是最新的角度和最新的角度材料。我有一个日期选择器,我想添加一些验证。文档说Javascript 角度5,角度材质:日期选择器验证不工作,javascript,angular,validation,typescript,angular-material2,Javascript,Angular,Validation,Typescript,Angular Material2,我使用的是最新的角度和最新的角度材料。我有一个日期选择器,我想添加一些验证。文档说required属性应该是现成的,但它似乎不像其他表单元素那样处理错误 这是我的分数: <mat-form-field class="full-width"> <input matInput [matDatepicker]="dob" placeholder="Date of birth" [(ngModel)]="myService.request.dob" #dob="ngModel"
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>
*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;
}
}
看一看,然后。请看一个基于javascript的示例
您还可以测试此(基于角度的)日期选择器: HTML:
您是否尝试将*ngIf设置为自定义验证器,如下所示:
<mat-error *ngIf="dob.errors && dob.errors.validateAdult">Your date of birth
is less than 18 ?</mat-error>
然后使用之前的ngIf,如下所示:
<mat-error *ngIf="dob.errors && dob.errors.requireValidator">Your date of
birth is less than 18 ?</mat-error>
您的注册日期
出生不足18岁?
我没有测试它,但从逻辑上讲它应该可以工作。您复制了#dob。在角度验证中可能会出现不希望出现的行为
你有
<input #dob='ngModel'
我在我的角度材质表单中使用了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>
您可以在这里看到更多信息:您可以更改输入引用的名称,如下所示。。
请注意,输入元素#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”
我在没有使用ErrorStateMatcher的情况下成功地实现了这一点,尽管这确实帮助我找到了解决方案。离开这里以备将来参考或帮助他人
我将表单转换为反应式表单,而不是模板驱动的表单,并将自定义验证器指令更改为更简单的验证器(基于非指令)
以下是工作代码:
my-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>
my-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);
}
在查看页面中添加以下内容:
<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谢谢,但所有链接都不相关。我不想使用不同的日期选择器,我不想使用Bootstrap或jQuery。我也没有使用AngularJS。问题不在于如何进行基于年龄的验证,而在于如何使用当前材料DatePickerHanks进行验证。是的,我确实将我的mat error
上的*ngIf
设置为dob.errors.validateDult
-这不是问题所在。通过断点,我可以看到,在选择了小于18年的日期的情况下,自定义指令工作正常,只是出于某种原因,它没有更新错误。我认为这是datepicker的问题,因为对于常规的matInput
元素,内置和自定义验证按预期工作。实际上,我使用自己的指令告诉输入检查模糊验证,但如果使用angular 5,则现在内置了模糊更新事件。因此,问题可能是控件没有获得更改检测来更新其错误。请按照下面的答案进行操作,希望它能解决您的问题:)。再次感谢,我在发布问题之前确实想到了这一点,并利用ChangeDetectorRef
触发手动更改检测,但这也不起作用。我确信这是datepicker本身的问题,也许可以尝试使用ErrorStateMatcher使错误立即出现。您可以添加详细信息和控制台日志吗?或错误屏幕。@如果没有错误屏幕或控制台错误,页面“工作”,甚至选择器附加的字段在拾取不到18年前的日期时也会显示红色错误样式,只是控件的errors
对象没有得到更新可能是一个输入错误,但是引用是在模型引用之后留下的。。。在[(ngModel)]=“myService.request.dob#dob=”ngModel“很好地发现了@Leonardonenger!但是,唉,这只是一个打字错误,无论如何,谢谢你!谢谢,这似乎是将控件与模型中的值联系起来所必需的。如果没有这一点,错误消息仍然没有显示,而且在选择日期时,我的模型也没有更新。但是我会在没有谢谢的情况下尝试,我会尝试这个,尽管这可能需要一些时间,因为我需要切换到反应式表单而不是模板表单
<mat-datepicker #dob></mat-datepicker>
<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();
}
<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>
[matDatepicker]="dob"
<mat-datepicker-toggle matSuffix [for]="dob"></mat-datepicker-toggle>
<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>
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;
};
}
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);
}
<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>