1

I want to add dynamic form array controls with the values according to response coming from API. If there 1 record then 1 row if 2 then 2 rows and so on.

Form:

this.VendorForm = this.formBuilder.group({
    vendorId: [null],
    vendorName: ['', [Validators.pattern(/^[A-Za-z\s]{1,}[\.]{0,1}[A-Za-z\s]{0,}$/), Validators.required]],
    vendorType: ['', Validators.required],
    correspondingAddressDetail: this.formBuilder.group({
      correspondingAddress: ['', Validators.required],
      correspondingState: ['', [Validators.required, Validators.pattern(/^[A-Za-z\s]{1,}[\.]{0,1}[A-Za-z\s]{0,}$/)]],
      correspondingPincode: ['', [Validators.required, Validators.pattern(/^\d{3}\d{3}$/)]],
      correspondingCity: ['', Validators.required],
      correspondingDistrict: ['', Validators.required],
      correspondingPostoffice: ['', Validators.required]
    }),
    billingAddressDetail: this.formBuilder.group({
      sameAddress: [false],
      billingAddress: ['', Validators.required],
      billingState: ['', [Validators.required, Validators.pattern(/^[A-Za-z\s]{1,}[\.]{0,1}[A-Za-z\s]{0,}$/)]],
      billingPincode: ['', [Validators.required, Validators.pattern(/^\d{3}\d{3}$/)]],
      billingCity: ['', Validators.required],
      billingDistrict: ['', Validators.required],
      billingPostoffice: ['', Validators.required]
    }),
    phoneNo: ['', [Validators.required, Validators.pattern(/^[1-9]\d{9}$/)]],
    email: ['', Validators.pattern(/^(\D)+(\w)*((\.(\w)+)?)+@(\D)+(\w)*((\.(\D)+(\w)*)+)?(\.)[a-z]{2,}$/)],
    contactPersonNo: ['', [Validators.required, Validators.pattern(/^[1-9]\d{9}$/)]],
    contactPersonName: ['', [Validators.required, Validators.pattern(/^[A-Za-z\s]{1,}[\.]{0,1}[A-Za-z\s]{0,}$/)]],
    contactPersonEmail: ['', Validators.pattern(/^(\D)+(\w)*((\.(\w)+)?)+@(\D)+(\w)*((\.(\D)+(\w)*)+)?(\.)[a-z]{2,}$/)],
    statutoryInfo: this.formBuilder.array([this.formBuilder.group({
      statutoryName: ['', Validators.required],
      info: ['', Validators.required]
    })]),
    isActive: [true],
    remarks: ['']
  });

patching value:

this.dialogData.statutoryInfo.forEach(x => {
      this.statutoryInfo.push(this.formBuilder.group({
        statutoryName: [x.statutoryName],
        info: [x.info]
      }))
    });

value of statutoryInfo coming from API response:

(2)[{…}, {…}]
0:{statutoryName: 6, info: '123456987'}
info:'123456987'
statutoryName:6
1:{statutoryName: 2, info: 'BnQpgw444'}
info:'BnQpgw444'
statutoryName:2 

after 1st click on Edit button:(throws error and the rows did not get inserted) throws error and the rows did not get inserted

after 2nd click on Edit button:(did not throw error and the rows did get inserted) enter image description here

I don't understand why after the second click the values got inserted. and I want to remove the empty row of formArray controls.

1 Answer 1

1

I had implemented exact same logic .ie. pushing form Array to formGroup depending upon number of the data from the API. Have a look at following necessary sample code. I hope it will provide you the solution to your problem.

    createForm() {
        this.editCityForm = this.formBuilder.group({
         state: ['', {
         validators: [Validators.required],
         }],
      
         things: this.formBuilder.array([])
      })

     // this add the form Array
     this.addThingToDoForm();

     }

    addThingToDoForm() {
       for (let i = 0; i < this.city.things.length; i++) {
         // this if condition prevents creating thingstodo form for {} empty objects.
         if (!this.checkIfObjectIsEmpty(this.city.things[i])) {
            this.things = this.editCityForm.get('things') as FormArray;
            this.things.push(this.createThingsToDo());
          }
        }
      }


    // these are fields inside formGroup of  formArray 
      createThingsToDo() {
        return this.formBuilder.group({
         id: [''],
         name: ['', {
          validators: [Validators.required],
          updateOn: 'blur'
          }],
        })
      }

    // it checks if object from API response is not empty so that 
   // we do not push form Array for empty response.
    checkIfObjectIsEmpty(obj) {
       return Object.keys(obj).length == 0;
     }

If you need to patchValue to the formArray , the following code gives you proper idea:

     patchThingsToDoForm() {
        const patchData = this.city.things;
        const thingsArray = this.editCityForm.get('things')['controls'];

        for (let i = 0; i < patchData.length; i++) {
          if (!this.checkIfObjectIsEmpty(this.city.things[i])) {
            const thingsToDoForm: FormGroup = thingsArray[i];
            thingsToDoForm.patchValue({
            id: patchData[i].id,
            name: patchData[i].name,
           })
           thingsToDoForm.updateValueAndValidity();
         }
       }

     }

Sign up to request clarification or add additional context in comments.

4 Comments

Method that you and I have used is working. except that after null checking on the API response the error goes away as you did. But the other problem did not get solved where the data does not get populated on the first click however after the second click it works fine . thanks for your help
As far as I understand , the error you are facing is clearly indicated from the console you have kept as screenshot. this.dialogData.statutoryInfo value is being undefined at the first time you click on the button. Please make sure that this value is obtained before the edit button is displayed so that this forEach loop could be executed without error.
It had something to do with the API call which I solved , thanks
Great. It would be very appreciable of you, if you could accept it as correct answer if you think it is correct. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.