简体   繁体   中英

Angular2 - Reactive Forms Validation

I am working on creating a validator for a set of inputs in my reactive form.

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>

For some reason, my error isn't showing up when I leave my end date empty for example. I feel like maybe I am calling the validator incorrectly? Compose was the only method I could find for chaining together multiple validators, but I am not sure if I need to pass anything with it?

Update:

Here is my full existing form, removing the validator from the individual controls. It also shows that i currently have a validator in place for this form, perhaps incorrectly.

How could I include multiple?

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

When building a validator for a control group, you need to add the validator to the group, not to the individual controls.

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

Also, you no longer need the compose ... That was for an earlier version of Angular.

I agree with Deborah, on having a nested formgroup for your dates. Why? Performance wise, especially if you have many (other) fields in your form, setting it validating whenever any field in the form changes, it would be fired unnecessary many times, so definitely do something like Deborah presented:

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

where it will be fired only when changes happen to the dates group.

As for your custom validator, you do not need to check if the dates are present, since you already have Validators.required , so change your custom validator to:

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

And to the question for trouble with showing the error message in template. It will not work with errors.invalidDates , you could use hasError . In this case you can quite neatly present the error with:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM