如何验证Angular中的两个字段?

时间:2017-10-31 09:33:15

标签: angular

我有两个字段。一个是最低价,另一个是最高价。我想验证最低价格应始终低于最高价格,最高价格应高于最低价格。在简单的正面情况下,它工作正常。

但它在某些情况下无效。

假设用户输入最小值为12,最大值为100。然后如果用户键入123332或某个大于100.it确实给出了错误消息。

<div class="col-md-3" >
<label for="minimumPriceTextbox" class="control-label">{{l("MinPrice")}}</label>
<input type="text"
       [minValue]="0" [maxValue]="test.maxPrice"
       maxlength="17" class="form-control c" id="minimumPriceTextbox"
       name="minimumPriceTextbox"
       placeholder="Minimum Price"
       [value]="test.minPrice"
       [(ngModel)]="test.minPrice"
       #minimumPriceTextbox="ngModel">
<div *ngIf="minimumPriceTextbox?.invalid && (minimumPriceTextbox?.dirty || minimumPriceTextbox?.touched)" class="has-error help-block help-block-error font-red-mint">
    <span> {{l("MinPriceShouldBeLessThanMaxPrice.")}} </span>
</div>
{{test.minPrice}}
</div>
<div class="col-md-3">
<label for="maximumPriceTextbox" class="control-label">{{l("MaxPrice")}}</label>
<input name="maximumPriceTextbox"
       type="text"
       [minValue]="test.minPrice"
       maxlength="17" class="form-control c" id="maximumPriceTextbox"
       placeholder="Maximum Price"
       [value]="test.maxPrice"
       [(ngModel)]="test.maxPrice"
       #maximumPriceTextbox="ngModel">
<div *ngIf="maximumPriceTextbox?.invalid && (maximumPriceTextbox?.dirty || maximumPriceTextbox?.touched)" class="has-error help-block help-block-error font-red-mint">
    <span> {{l("MaxPriceShouldBeGreaterThanMinPrice.")}} </span>
</div>
{{test.maxPrice}}
</div>

minValue指令代码:

import { Directive, forwardRef, Attribute, Input } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';


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

    @Input('minValue') minValue: number;

    validate(control: AbstractControl): { [key: number]: any } {
        let givenvalue = control.value;
        let validationResult = null;

        let minValue = this.minValue;
        if (minValue && givenvalue < minValue) {
            validationResult = validationResult || {};
            validationResult.minValue = true;
        }

        return validationResult;
    }
}

maxValue指令代码:

import { Directive, forwardRef, Attribute, Input } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';


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

    @Input('maxValue') maxValue: number;

    validate(control: AbstractControl): { [key: number]: any } {
        let givenvalue = control.value;
        let validationResult = null;

        let maxValue = this.maxValue;
        if (maxValue && givenvalue > maxValue) {
            validationResult = validationResult || {};
            validationResult.maxValue = true;
        }

        return validationResult;
    }
}

2 个答案:

答案 0 :(得分:1)

没有简单的方法来进行交叉验证,但是可以创建自己的自定义验证器指令,其目的是将表单组件名称传递给验证器并在验证器中订阅这些组件的更改:

export interface IValidatorFactory
{
    (input:any, key:string):SyncValidatorResult;
}

@Directive({
    selector : 'input[sync]',
    exportAs : 'sync',
    providers: [{provide: NG_VALIDATORS, useExisting: forwardRef(() => GenericValidator), multi: true}]
})
export class GenericValidator implements AsyncValidator, OnInit
{
    @Input('sync')
    public factory:IValidatorFactory;

    @Input('deps')
    public deps:string[];

    private onChange:() => void;

    private readonly form:FormGroup;

    constructor(form:NgForm)
    {
        this.form = form.form;
    }

    public ngOnInit():any
    {
        //wait for ngmodel created
        setTimeout(() =>
        {
            if(Array.isArray(this.deps) && this.deps.length > 0)
            {
                const values:any = Object.create(null);

                for(const controlName of this.deps)
                {
                    const control = this.form.get(controlName);
                    if(control == null)
                    {
                        console.error('Dependant control was not found', controlName);
                    }
                    else
                    {
                        control.valueChanges.subscribe(changes =>
                        {
                            if(values[controlName] !== changes)
                            {
                                values[controlName] = changes;
                                this.onChange();
                            }
                        });
                    }
                }
            }
        }, 0);
    }

    public registerOnValidatorChange(fn:() => void):void
    {
        this.onChange = fn;
    }

    public validate(c:AbstractControl):AsyncValidatorResult;
    public validate(c:AbstractControl):SyncValidatorResult
    {
        return this.validatorFn(c);
    }

    private validatorFn(formControl:AbstractControl):SyncValidatorResult
    {
        if(formControl.value != null && this.factory != null)
        {
            return this.factory(formControl.value, 'syncValidator');
        }
        return null;
    }
}

    public onValidate(c:AbstractControl):ValidatorResult
    {
        return this.validatorFn(c);
    }

    private validatorFn(formControl:AbstractControl):SyncValidatorResult
    {
        if(formControl.value != null && this.factory != null)
        {
            return this.factory(formControl.value, 'syncValidator');
        }
        return null;
    }
}

模板:

    <input name="field1" type="text" [(ngModel)]="item.field1" [sync]="validateFields" [deps]="['field2']"></div>
    <input name="field2" type="text" [(ngModel)]="item.field2" [sync]="validateFields" [deps]="['field1']"></div>

组件:

public validateFields:IValidatorFactory = (value:string, key:string):SyncValidatorResult =>
{
    let result:SyncValidatorResult = null;

    if(...)
    {
        result = Object.create(null);
        result[key] = {
            valid  : false,
            message: 'invalid values'
        };
    }
    return result;
};

答案 1 :(得分:0)

代替指令,你不能使用简单的函数吗?有点像(对不起,我会将代码减少到最小)

<input type="number" (input)="checkValidity()" [(ngModel)]="maxValue">

在你的TS中:

checkValidity() {
  if (this.maxValue < this.minValue) { /* Set your error here */ }
  else if (this.minValue > this.maxValue) { /* Set your error here */ }
  else { /* Set your other errors, or your validation here */ }
}