Search code examples
angularvalidationreactiveformarrayangular-formbuilder

Angular 9 FormArray Conditional Validation - subscribe issue


I'm having trouble with being able to subscribe to valueChanges of a form that uses FormArray inside of FormGroup. Essentially, I need to know the value of one input as that changes the validation rules of another. Below is an example of how I have successfully implemented the same concept with a FormBuilder group:

  myForm = this.fb.group({
    myFirstField: ['', Validators.required],
    mySecondField: ['']
  });

  constructor(
    private fb: FormBuilder
  ) { }

  ngOnInit(): void {
    this.myForm.get('myFirstField').valueChanges.subscribe(myFirstFieldVal => {
      if (myFirstFieldVal === 'something') {
        this.myForm.controls.mySecondField.setValidators([Validators.required]);
      } else {
        this.myForm.controls.mySecondField.clearValidators();
      }
      this.myForm.controls.mySecondField.updateValueAndValidity();
    });
  }

And beneath is my attempt at using the same concept with a FormArray. The form itself works in the template with outputting the data and submitting etc. but I need to add some conditional validation within each array. Below is not doing the trick. Any ideas how I can subscribe to the valueChanges of certain fields in each group?

import { Component, OnInit, Input } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
import { BehaviorSubject } from 'rxjs';

export interface ExampleGroup {
  myFirstField: string;
  mySecondField: string;
}
export class ExampleFormComponent implements OnInit {
  dataSource = new BehaviorSubject < AbstractControl[] > ([]);
  myFormArr: FormArray = this.fb.array([]);
  myFormGroups: FormGroup = this.fb.group({
    exampleGroups: this.myFormArr
  });
  exampleData = [{
    myFirstField: 'something',
    mySecondField: 'something else',
  }, {
    myFirstField: 'blah',
    mySecondField: '',
  }, ];
  constructor(private fb: FormBuilder, ) {}
  ngOnInit(): void {
    // doesn't work
    this.myFormArr.controls.forEach((control, index) => {
      control.get('myFirstField').valueChanges.subscribe(myFirstFieldVal => {
          console.log(control); // doesn't even get to here
        if (myFirstFieldVal === 'something') {
          this.myFormArr.controls.mySecondField.setValidators([Validators.required]);
        } else {
          this.myFormArr.controls.mySecondField.clearValidators();
        }
        this.myForm.controls.mySecondField.updateValueAndValidity();
      });
    });
    this.exampleData.forEach((d: ExampleGroup) => this.addToMyFormArr(d, false));
  }
  addToMyFormArr(d ? : ExampleGroup) {
    const groupToAdd = this.fb.group({
      myFirstField: [
        d && d.myFirstField ? d.myFirstField : '',
        Validators.required, []
      ],
      mySecondField: [d && d.mySecondField ? d.mySecondField : '', []],
    });
    this.myFormArr.push(groupToAdd);
  }
}

Solution

  • This issue was occurring because in my code the forEach subscribe was being called after addToMyFormArr() unlike in the code example I provided in the question. I have updated the code example to reflect how the issue was occurring.