Angular2 - 反应式表单验证

Angular2 - Reactive Forms Validation

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

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);
        }
    });

为控制组构建验证器时,您需要将验证器添加到组中,而不是单独的控件中。

    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()])
    });

此外,您不再需要 compose ...那是针对早期版本的 Angular。

我同意 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')">