Search code examples
angularangular-materialangular-reactive-forms

How to get all form controls inside a custom validator (field groups dynamically created)


I am building a dynamic form, using form builder as below:

runnable code I have been trying so far in stackblitz

I have read docs and seen this e.g. but couldn't find an example where the other dynamically added form control values are fetched and do some action with them ..

Here I wanted to check the sum of current entered count field and the rest of the count fields is less than the availableCount ... If it is greater I wanted to show / return an error and make the current control invalid

I understood the part of returning an object from customValidator, but the way I am trying in my above code is giving me errros on getting the feildsArray from form, not sure what I am missing though ..

I took AI help too but couldn't get it correct ... any help is appreciated, thanks


Solution

  • When you use a formArray and want to control, you should create the validator over the formArray or check all the elements of the array each time you change

    NOTE: I don't like use the "ugly bind", so simply access to the formArray from control using, in this case control?.parent?.parent as FormArray

    Well, if "availableCount" can change after we create the formGroup, we need use bind, else we can do

    countFieldValidator(limit:number){
        return (control: FormControl)=>{
        const fieldsArray = control?.parent?.parent as FormArray;
        if (fieldsArray) {
          const totalCount = fieldsArray?.controls
            .map((fieldGroup) => fieldGroup.get('count')?.value)
            .reduce((sum, count) => sum + (count || 0), 0);
    
          if (totalCount > limit) {
            return { countExceeded: true };
          }
          //if there're no errors we checked all the other with error
          //if we use bind or not we need check
          fieldsArray.controls.forEach(x=>{
            const other=x.get('count')
            if (other!=control && other.invalid)
              other.updateValueAndValidity()
          })
    
        }
        return null;
      }
    }
    

    And write

    count: [
        null,
        [
          Validators.required,
          Validators.min(1),
          this.countFieldValidator(this.availableCount),
        ],