我正在开发一个saveialog,它接受任何带有字符串,布尔值和日期字段的简单对象。我已经构建了一个组件来构建它,现在我想动态地将验证添加到已经创建的输入字段中。
我在TypeScript中编程,使用Angular2,还有一个名为PrimeNG的框架,它是PrimeFaces的Angular2版本。
HTML
<p-dialog #dialog header="{{dialogTitle}}" [(visible)]="isDisplayed" [responsive]="true" showEffect="fade"
[modal]="true" [closable]="false" [closeOnEscape]="false" [modal]="true" [width]="1000" [resizable]="false">
<form novalidate #form (ngSubmit)="save()">
<div class="ui-grid ui-grid-responsive ui-fluid" *ngIf="saveObject">
<div *ngFor="let i of rows" class="ui-grid-row">
<div class="ui-grid-col-6" *ngFor="let field of fields | slice:(i*itemsPerRow):(i+1)*itemsPerRow">
<div class="ui-grid-col-5 field-label">
<label for="attribute">{{field.key}}</label>
</div>
<div class="ui-grid-col-5">
<p-checkbox *ngIf="booleanFields.indexOf(field.key) !== -1" binary="true"
[(ngModel)]="saveObject[field.key]" name="{{field.key}}"
[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
[valueValidator]="field.key" [validateObject]="saveObject"></p-checkbox>
<p-calendar *ngIf="dateFields.indexOf(field.key) !== -1" [(ngModel)]="saveObject[field.key]"
name="{{field.key}}"
[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
dateFormat="dd/mm/yy" [showIcon]="true" [appendTo]="dialog"
[monthNavigator]="true"
[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
[valueValidator]="field.key"
[validateObject]="saveObject"></p-calendar>
<input *ngIf="(booleanFields.indexOf(field.key) === -1) && (dateFields.indexOf(field.key) === -1)"
pInputText id="attribute" [(ngModel)]="saveObject[field.key]" name="{{field.key}}"
[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
[valueValidator]="field.key" [validateObject]="saveObject"/>
</div>
</div>
</div>
</div>
</form>
<p-footer>
<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix">
<button label=" " type="button" pButton (click)="hideDialog(true)">
<i class="fa fa-times fa-fw" aria-hidden="true"></i>Sluit
</button>
<button label=" " type="submit" pButton (click)="hideDialog(false)" [disabled]="!form.valid">
<i class="fa fa-check fa-fw" aria-hidden="true"></i>Opslaan
</button>
</div>
</p-footer>
SaveDialogComponent
import { Component, Input, Output, OnChanges, EventEmitter } from '@angular/core';
import { FieldUtils } from '../utils/fieldUtils';
import { ValueListService } from '../value-list/value-list.service';
@Component({
moduleId: module.id,
selector: 'save-dialog',
templateUrl: 'savedialog.component.html',
styleUrls: ['savedialog.component.css']
})
export class SaveDialogComponent implements OnChanges {
@Input() dialogTitle:string;
@Input() isDisplayed:boolean;
@Input() saveObject:any;
@Input() unwantedFields:string[] = [];
@Input() booleanFields:string[] = [];
@Input() dateFields:string[] = [];
@Output() hide:EventEmitter<boolean> = new EventEmitter<boolean>();
@Output() result:EventEmitter<Object> = new EventEmitter<any>();
private fields:any[];
private itemsPerRow:number = 2;
private rows:any[];
ngOnChanges() {
this.fields = FieldUtils.getFieldsWithValues(this.saveObject, this.unwantedFields);
this.rows = Array.from(Array(Math.ceil(this.fields.length / this.itemsPerRow)).keys());
}
hideDialog(clearChanges:boolean) {
if(clearChanges){
this.resetObject()
}
this.isDisplayed = false;
this.hide.emit(this.isDisplayed);
}
save() {
this.result.emit(this.saveObject);
}
private resetObject() {
for(let field of this.fields) {
this.saveObject[field.key] = field.value;
}
}
private getDate(date:string):Date {
return new Date(date);
}
}
我不包括字段工具,因为它并不重要,基本上它从一个对象中提取所有字段,使用booleanFields和dateFields来排序字段以便放置一个字段的所有字段相同的类型彼此相邻。
ValidatorDirective
import { Directive, Input } from '@angular/core';
import { AbstractControl, ValidatorFn, Validator, NG_VALIDATORS, FormControl } from '@angular/forms';
@Directive({
selector: '[valueValidator][ngModel]',
providers: [
{provide: NG_VALIDATORS, useExisting: ValueValidatorDirective, multi: true}
]
})
export class ValueValidatorDirective implements Validator {
@Input('valueValidator') fieldName:string;
@Input() validateObject:any;
@Input() values:any[];
datumStartValidator:ValidatorFn;
datumEindValidator:ValidatorFn;
codeValidator:ValidatorFn;
naamValidator:ValidatorFn;
volgNrValidator:ValidatorFn;
validate(c:FormControl) {
this.instantiateFields();
switch (this.fieldName) {
case 'datumStart':
return this.datumStartValidator(c);
case 'datumEind':
return this.datumEindValidator(c);
case 'code':
return this.codeValidator(c);
case 'naam':
return this.naamValidator(c);
case 'volgnr':
return this.volgNrValidator(c);
default :
return {
error: {
valid: false
}
}
}
}
instantiateFields() {
this.datumStartValidator = validateStartDatum(this.validateObject['datumEind']);
this.datumEindValidator = validateEindDatum(this.validateObject['datumStart']);
this.codeValidator = validateCode();
this.naamValidator = validateNaam();
this.volgNrValidator = validateVolgNr(null);
}
}
//We'll need multiple validator-functions here. one for each field.
function validateStartDatum(datumEind:Date):ValidatorFn {
return (c:AbstractControl) => {
let startDatum:Date = c.value;
let isNotNull:boolean = startDatum !== null;
let isBeforeEind:boolean = false;
if (isNotNull) {
isBeforeEind = datumEind.getTime() > startDatum.getTime();
}
if (isNotNull && isBeforeEind) {
return null
} else {
return returnError();
}
}
}
function validateEindDatum(startDatum:Date):ValidatorFn {
return (c:AbstractControl) => {
let eindDatum:Date = c.value;
let isNotNull:boolean = eindDatum !== null;
let isBeforeEind:boolean = false;
if (isNotNull) {
isBeforeEind = eindDatum.getTime() > startDatum.getTime();
}
if (isNotNull && isBeforeEind) {
return null
} else {
return returnError();
}
}
}
function validateCode():ValidatorFn {
return (c:AbstractControl) => {
let code:string = c.value;
if (code !== null) {
return null;
} else {
return returnError();
}
}
}
function validateNaam():ValidatorFn {
return (c:AbstractControl) => {
let naam:string = c.value;
if (naam !== null) {
return null;
} else {
return returnError();
}
}
}
function validateVolgNr(volgnummers:string[]):ValidatorFn {
return (c:AbstractControl) => {
return returnError();
}
}
function returnError():any {
return {
error: {
valid: false
}
}
}
首先,我想说谢谢你一直读到这个,你是一个冠军!我知道我的代码并不是你见过的最好的代码,但我现在只是想让它工作。我目前遇到的问题是验证发生但我似乎无法使用
设置类[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
发现field.key没问题但我似乎无法将其用作对输入字段的动态名称的引用。 field.key.errors未定义,我猜是可以预料到的。但我还没有找到解决这个问题的方法。
其次我认为我的方式现在我最终会遇到整个表单验证的问题(禁用提交按钮)
<button label=" " type="submit" pButton (click)="hideDialog(false)" [disabled]="!form.valid">
欢迎任何关于如何解决此问题的想法,我对所有建议持开放态度。