Angular2 - 使用旧数据的自定义验证器

时间:2017-02-10 14:51:15

标签: validation angular

我遇到过我自己编写的自定义验证程序的问题。验证器用于验证组件中的所有数据。

以下是设置:

该组件显示一个包含X行数据的表。某些行是仅显示模式,而其他行将处于编辑模式(表中的某些单元格将具有输入,选择等)。支持表是一个数据对象数组(tableData)。

如果一行处于编辑模式,则每个输入都与tableData数组中的相应元素双向绑定。

我的自定义验证器应用于表单标记,并将tableData作为输入。一切都很有效。验证数据查看表中的每一行,并执行我需要它执行的所有操作。

问题是基于我的自定义验证程序的数据是旧数据。因此,如果一行处于编辑模式,当我更改select中的值时,tableData会更新,但是传递给验证程序的版本在更新之前。所以我总是在验证旧版本的tableData。

我不确定如何使用最新版本的tableData进行验证。我认为这个问题可能与select绑定更改tableData数组中对象的值这一事实有关,但tableData数组本身并没有实际更改。

我尝试在正在编辑的行中的select上添加回调(change)事件。手动调用(更改)的方法使用ChangeDetectorRef触发更改检测,但这不起作用。

我不想用所有文件向所有人发送垃圾邮件,因此我尝试添加重要的代码段。

这是模板:

<form #f="ngForm" novalidate custom-validator="{{tableData | json}}">
    <p-dataTable [value]="tableData">
    ...

        <p-column [header]="'Program Name'">
            <template let-row="rowData" let-idx="rowIndex" pTemplate type="body">
            <span *ngIf="!row['edit']">
                {{row['data'].programName}}
            </span>
                <div *ngIf="row['edit']">
                    <select #progName="ngModel" [(ngModel)]="row['data'].programCode"
                            title="Select Program" required (change)="onProgramChange($event, idx)"
                            name="programSelect-{{idx}}">
                        <option [value]=""></option>
                        <option *ngFor="let prog of programList" [value]="prog.code">
                            {{prog.name}}
                        </option>
                    </select>
                </div>
            </template>
        </p-column>
    ...

    </p-dataTable>
</form>

这是支持组件:

//imports...

...

private tableData: PersonAssignmentRowData[] = [];
private programList: Program[] = [];

...

onProgramChange(event: any, index: number) {

    for(let prog of this.programList) {
        if(prog.code == event.target.value) {
            this.tableData[index].data.programAcronym = prog.acronym;
            this.tableData[index].data.programLocation = prog.location;
            this.tableData[index].data.programName = prog.name;
            break;
        }
    }
}

...

这是验证员:

@Directive({
    selector: '[custom-validator]',
    providers:[{provide: NG_VALIDATORS, useExisting: CustomValidator, multi: true}]
})
export class CustomValidator implements Validator{

    @Input('custom-validator') tableDataString: string;

    validate(control: AbstractControl) {
        if(this.tableDataString == null || this.tableDataString.length == 0) {
            return null;
        }

        let tableData: PersonAssignmentRowData[] = [];
        tableData = JSON.parse(this.tableDataString);

        let message: string = '';

        //logic that tests the validity of the data and sets any error messages in the message variable

        if(message.length > 0) {
            return {'validationMessage': message};
        } else {
            return null;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

现在很清楚了。当然它不会起作用。验证器应检查的唯一数据源是传递给validate()方法的控件。没有@Inputs()或类似的东西。唯一的区别是下面的control.value将包含表单中所有控件的所有值,而不仅仅是表格,因此您应该在表格中选择正确的嵌套值。

@Directive({
    selector: '[custom-validator]',
    providers:[{provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidator), multi: true}]
})
export class CustomValidator implements Validator {

    validate(control: AbstractControl) {
        tableData = control.table.value; // need to figure out exact path based on your form structure

        let message: string = '';

        //logic that tests the validity of the data and sets any error messages in the message variable

        if(message.length > 0) {
            return {'validationMessage': message};
        }
        return null;
    }

}