19

In an Angular 4 application, how can I validate two fields of a form doing a comparison?

For example, let's suppose that my form has a startDate and an endDate date fields and I want to make sure that the endDate must be bigger than the startDate.

Francesco Borzi
  • 56,083
  • 47
  • 179
  • 252

2 Answers2

28

When you want to implement validations containing one or more sibling (form)controls, you have to define the validator function on a level up/above that of the sibling controls. For ex:

ngOnInit() {
    this.form = this.formbuilder.group({
        'startDate': ['', [<control-specific - validations >]],
        'endDate': ['', [<control-specific - validations >]]
    }, { validator: checkIfEndDateAfterStartDate });
}

Then outside the component class's definition (in the same file), define the function checkIfEndDateAfterStartDate as well.

export function checkIfEndDateAfterStartDate (c: AbstractControl) {
    //safety check
    if (!c.get('startDate').value || !c.get('endDate').value) { return null }
    // carry out the actual date checks here for is-endDate-after-startDate
    // if valid, return null,
    // if invalid, return an error object (any arbitrary name), like, return { invalidEndDate: true }
    // make sure it always returns a 'null' for valid or non-relevant cases, and a 'non-null' object for when an error should be raised on the formGroup
}

This validation will make the FormGroup invalid by adding the error-flag (here invalidEndDate) to true to the errors object for that FormGroup. If you want to have specific errors to be set on any of the sibling controls instead, then you can manually set the error flags on that formControl by using something like, c.get('endDate').setErrors({ invalidEndDate: true }). If you do this, then make sure you clear them for a valid case by setting the errors to null like this, c.get('endDate').setErrors(null).

A live demo of a similar validation can be seen here.

Ollie
  • 1,641
  • 1
  • 13
  • 31
amal
  • 3,140
  • 1
  • 13
  • 20
  • I don't think you need to export the check function. Also why have you declared `c` as `AbstractControl` and not just `FormGroup` ? – Francesco Borzi Sep 14 '17 at 13:27
  • 2
    Yes, you don't necessarily have to 'export' the function if it is in the same file. I declared it as an `AbstractControl` since it is the base class for `FormGroup`s (and also for `FormControl`s and `FormArray`s). No harm in doing that. Also helps you use all the properties defined in that class 'typescript'-ically. – amal Sep 14 '17 at 13:30
  • 1
    @ShinDarth Can you please post you code .html with .ts ? i'm fascing the same situation . thank's in advance :) – dEs12ZER May 29 '18 at 17:10
0

try this

export class validationComponent implements OnInit {
     private testForm:FormGroup;

     constructor(private fb: FormBuilder) {

     }

     ngOnInit() {
         this.testForm = this.fb.group({
           'startDate': ['', [Validators.required]],
           'endDate': ['', [Validators.required]]
        });

       this.subscribeDateChanges();
    }

    subscribeDateChanges() {
        const startDateChanges = (<any>this.testForm).controls.startDate.valueChanges;
        const endDateChanges = (<any>this.testForm).controls.endDate.valueChanges;

        startDateChanges.subscribe(start => {
             this.testForm.controls['endDate'].
               setValidators(
                [Validators.required,
                CustomValidators.minDate(this.toYYYYMMDD(start))]);
        this.validateDates();
       });

       endDateChanges.subscribe(end => {
               this.validateDates();
         });
     }

   dateError: boolean = false;
   validateDates(): void{
       let startDate = this.testForm.controls['startDate'].value;
       let endDate = this.testForm.controls['endDate'].value;
       if(endDate && startDate){
           this.dateError = endDate <= startDate;
        }
    }

   toYYYYMMDD(d:Date): string {
       d = new Date(d)
       var yyyy = d.getFullYear().toString();
       var mm = (d.getMonth() + 101).toString().slice(-2);
       var dd = (d.getDate() + 100).toString().slice(-2);
       return yyyy + '-' +  mm + '-'  + dd;
   }

based on the dateError boolean value you show error msg

Robert
  • 3,373
  • 1
  • 18
  • 34