Angular2 - 反应式表单验证

时间:2017-07-27 14:40:43

标签: angular typescript angular-reactive-forms

我正在为我的被动形式的一组输入创建一个验证器。

this.transitionForm = this.fb.group({
  effectiveStartDate: [this.utils.dateToISO(startDate), Validators.compose([Validators.required, this.validateDates])],
  effectiveEndDate: [(endDate ? endDate : ''), Validators.compose([Validators.required, this.validateDates])],
});

/**
 * Checks to make sure the start and end date selected
 * are in an acceptable format.
 *
 * @param formGroup
 */
validateDates(formgroup: FormGroup) {

    const start = formgroup.controls["effectiveStartDate"].value;
    const end = formgroup.controls["effectiveEndDate"].value;

    /**
     *   Validation Logic
     * - End date cannot come before start date
     * - Start date cannot come after end date
     * - Start date cannot be empty
     * - End Date cannot be empty
     */
    if ((end < start) || (start > end) || !start || !end) {
        return { invalidDates: true };
    } else {
        return null;
    }
}

HTML:

<div *ngIf="!transitionForm.controls['effectiveEndDate'].valid">
 <p *ngIf="transitionForm.controls['effectiveEndDate'].errors.invalidDates">
  Invalid End Dates
 </p>
</div>

出于某种原因,例如,当我将结束日期留空时,我的错误没有显示出来。我觉得我可能错误地调用了验证器? Compose是我能找到的将多个验证器链接在一起的唯一方法,但我不确定是否需要传递任何内容?

更新

这是我现有的完整表单,从各个控件中删除验证器。它还表明我目前有一个验证器,可能是错误的。

我怎么能包含多个?

this.transitionForm = this.fb.group({
    changeType: ['', Validators.required],
    effectiveStartDate: [this.utils.dateToISO(startDate), Validators.required],
    effectiveEndDate: [(endDate ? endDate : ''), Validators.required],

},
    {
        // Validate to make sure we selected at least one transition field
        validator: (formGroup: FormGroup) => {
            return this.validateFilter(formGroup);
        }
    });

2 个答案:

答案 0 :(得分:1)

为控制组构建验证器时,需要将验证器添加到组中,而不是添加到各个控件。

    this.customerForm = this.fb.group({
        firstName: ['', [Validators.required, Validators.minLength(3)]],
        lastName: ['', [Validators.required, Validators.maxLength(50)]],
        emailGroup: this.fb.group({
            email: ['', [Validators.required, Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+')]],
            confirmEmail: ['', Validators.required],
        }, {validator: emailMatcher}),
        phone: '',
        notification: 'email',
        rating: ['', ratingRange(1, 5)],
        sendCatalog: true,
        addresses: this.fb.array([this.buildAddress()])
    });

此外,您不再需要撰写...这是早期版本的Angular。

答案 1 :(得分:1)

我同意Deborah的观点,即为您的日期设置嵌套表单组。 为什么?性能明智,特别是如果你的表单中有很多(其他)字段,设置它验证表单中的任何字段发生变化时,它会被多次激活,所以肯定做像Deborah这样的事情提出:

...
dates: this.fb.group({
  effectiveStartDate: [this.utils.dateToISO(startDate), Validators.required],
  effectiveEndDate: [(endDate ? endDate : ''), Validators.required],
},{validator: this.validateDates})
...

只有在dates组发生更改时才会触发它。

对于您的自定义验证程序,您无需检查日期是否存在,因为您已经有Validators.required,因此请将自定义验证程序更改为:

validateDates(dates: FormGroup) { // here is the 'dates' formgroup (only)
  const start = dates.controls["effectiveStartDate"].value;
  const end = dates.controls["effectiveEndDate"].value;

  if ((end < start) || (start > end)) {
     return { invalidDates: true };
  } else {
     return null;
  }
}

以及在模板中显示错误消息的问题。它不适用于errors.invalidDates,您可以使用hasError。在这种情况下,您可以非常巧妙地呈现错误:

<p *ngIf="transitionForm.hasError('invalidDates', 'dates')">