Search code examples
angularangular-reactive-formsangular4-formsangular-forms

Comparing Amount in Reactive Forms in Angular


I need to compare the amount from the applied_amount. However they are on different controls but they are on the same formgroup. How should i check if the "amount" is greater than the "applied_amount"? Here's the code below.

 this.reportForm = this.fb.group({
                employee_id: [null, Validators.required],
                outlet_id: [null, Validators.required],
                grand_total: new FormControl({value: null, disabled: true}, Validators.required),
                rows: this.fb.array([]),
                applied_amount: [null, Validators.required],
            });


initGroup() {
        let rows = this.reportForm.get('rows') as FormArray;
        rows.push(this.fb.group({
            expense_account: ['', Validators.required],
            description: ['', Validators.required],
            amount: ['', Validators.required],
        },{validator: this.customValidator(rows)}))
    }



customValidator(group: any) {
        if ((group.controls.amount.value > group.parent.parent.controls.applied_amount.value)) {
            return { out1: true }
        }
        return null;
    }

Solution

  • First of all you shouldn't call method customValidator method as mentioned @Boris Lobanov

    It says it cannot read parent of undefined

    That is because when angular creates FormGroup through FormBuilder::group it also calls validators but current group doesn't have parent yet. The parent will be set only after FormArray::push.

    So the solution could look like:

    validator: this.customValidator
    ...
    
    customValidator(group: any) {
      if (!group.parent ) {
          return;
      }
      ...
    

    I also fire validation for all rows when applied_amount is changed.

    html

    <input type="number" formControlName="applied_amount" (ngModelChange)="validateAllRows()">
    

    ts

    validateAllRows() {
      const rows = this.reportForm.get('rows') as FormArray;
    
      rows.controls.forEach(group => {
        group.updateValueAndValidity();
      })
    }
    

    Ng-run Example

    Another solution is almost the same like yours:

    validator: this.customValidator.bind(rows)
    ...
    
    customValidator(this: FormArray, group: any) {
      if (group.controls.amount.value > this.parent.controls['applied_amount'].value) {
        return { out1: true }
      }
      return null;
    }
    

    Here I use Function.prototype.bind method to pass FormArray directly to your validator.