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

2 Custom validator not working in reactive forms in Angular


I need to figure out how will i be able to add the second validator in my reactive forms. I've added the "AvailabilityBalanceValidator" to the patchValues() which initialize the rows. However only the first validator is working, how come the second validator which is the AvailabilityBalanceValidator() is not working. Please check this link CHECK THIS LINK

patchValues() {
    const materialForms = this.orders
      .reduce((acc, i) => [...acc, ...i.materials], [])
      .map(x => {
        return (this.fb.group({
          checkbox_value: [null],
          material_id: [{ value: x.id, disabled: true }],
          material_name: x.name,
          available_qty: 10,
          quantity: [null]
        }, [this.subFormValidator.bind(this), { validator: this.AvailabilityBalanceValidator('available_qty', 'quantity') }]));
      });

    this.myForm.setControl('rows', this.fb.array(materialForms));
    this.myForm.setValidators([this.formValidator.bind(this)])
  }

  AvailabilityBalanceValidator(campo1: string, campo2: string) {
    return (group: FormGroup): { [key: string]: any } => {
      const balance = group.controls[campo1];
      const quantity = group.controls[campo2];
      if (balance.value < quantity.value) {
        return {
          out: true
        };
      }
    };
  }

Solution

  • I figured out why your second validator does not work. In fact the adding of the validators is wrong.

    You assigned your validators array as second parameter of the this.fb.group() method :

    this.fb.group({...}, [this.subFormValidator.bind(this), { validator: this.AvailabilityBalanceValidator('available_qty', 'quantity') }];
    

    The method FormBuilder.group receives as second parameter an object with two possible parameters validator and asyncValidator (see docs).

    To fix your missing validation you should change your code like follow:

    this.fb.group({...}, {
        validator: Validators.compose([this.subFormValidator.bind(this), this.AvailabilityBalanceValidator('available_qty', 'quantity')])
    };
    

    Update:

    subFormValidator(control: AbstractControl): { [key: string]: any } {
        return control.value.checkbox_value && 
            // Only adds the error if quantity is not set or it's an empty string
            (!control.value.quantity || control.value.quantity.length === 0)? { 'req': 'This field is required' } : null
    }
    

    And in your html:

    <small class="form-text text-muted danger" *ngIf="row.hasError('req')">This field is required</small>
    

    Because otherwise the message is always shown, if the control has an error.