将验证添加到动态构造的表单

时间:2017-03-22 14:23:31

标签: forms validation angular typescript primeng

方案

我正在开发一个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">

欢迎任何关于如何解决此问题的想法,我对所有建议持开放态度。

0 个答案:

没有答案