Search code examples
angularangular-reactive-formsformarray

How to preset values of reactive form in FormArray?


I have a reactive form with some dynamic field. I am trying to build a CRUD operation. Where "Create" is working fine but to update form I need to prepopulate fields. I can prepopulate the fields which are not in "FormArray" but as I am using some dynamic filed I want to show data in dynamic fields also.

Here is my sample payload which I have to prepopulate in form: `

scriptRunnerData: any = {
    "workflow_name": "vvvv",
    "runnerNodes": [
        {
            "script_name": "sample.py",
            "script_file_content": "jhsvdfhskjdhfvksdj fksjd"
        },
        {
            "script_name": "sample1.py",
            "script_file_content": "sdfjhdsbf sjd fsjd sd dfsb dlfsdjf sd  fls"
        }
    ],
    "executer_command": "dfhdhdjhkdfkdhfg.py",
    "config_name": "config.json",
    "config_file_content": "{\"name\":\"vvvv\"}"
  }

I am passing modes 'create' and 'edit'. Create is working fine but for View I am getting error:ERROR Error: Cannot find control with path: 'runnerNodes -> 0 -> script_name'andERROR Error: Cannot find control with path: 'runnerNodes -> 0 -> script_file_content'`

Here is my code: `

createWorkflowAddFormBuilderObj(){
    if(this.data.mode === 'create'){
      console.log("data", this.data);
      this.workflowAddForm = this.formBuilder.group({
        workflow_name: '',
        runnerNodes: this.formBuilder.array([ this.createRunnerNode() ]),
        executer_command: '',
        config_name: '',
        config_file_content: ''
      });
     }else if(this.data.mode === 'edit'){
      this.workflowAddForm = this.formBuilder.group({
        workflow_name: [{value: this.scriptRunnerData.workflow_name, disabled: false}],
        runnerNodes: this.formBuilder.array([ this.createRunnerNode() ]),
        executer_command: [{value: this.scriptRunnerData.executer_command, disabled: false}],
        config_name: [{value: this.scriptRunnerData.config_name, disabled: false}],
        config_file_content: [{value: this.scriptRunnerData.config_file_content, disabled: false}]
      });
    }
    
  }

  createRunnerNode(): FormGroup {
    if(this.data.mode === 'create'){
      return this.formBuilder.group({
        script_name: '',
        script_file_content: ['', Validators.required]
      });
    }else if(this.data.mode === 'edit'){
      this.scriptRunnerData.runnerNodes.forEach(node =>{
        return this.formBuilder.group({
          script_name: [{value: node.script_name, disabled: false}],
          script_file_content: [{value: node.script_file_content, disabled: false}, Validators.required]
        });
      })
    }
  }

  addMoreRunner(){
    this.runnerNodes = this.workflowAddForm.get('runnerNodes') as FormArray;
    this.runnerNodes.push(this.createRunnerNode());
    this.runnerNodeLength = this.runnerNodes.controls.length;
  }

Can anyone please suggest what exactly I have to do. IssetValueORpatchValue` will work here. How to use those methods with this scenario. Thanks in advance.


Solution

  • I have modified createWorkflowAddFormBuilderObj()

    createWorkflowAddFormBuilderObj(){
        if(this.data.mode === 'create'){
          console.log("data", this.data);
          this.workflowAddForm = this.formBuilder.group({
            workflow_name: '',
            runnerNodes: this.formBuilder.array([ this.createRunnerNode() ]),
            executer_command: '',
            config_name: '',
            config_file_content: ''
          });
         }else if(this.data.mode === 'edit'){
          const controls = this.scriptRunnerData.runnerNodes.map((c) =>
            this.formBuilder.group({
              script_name: [{value: c.script_name, disabled: true}],
              script_file_content: [{value: c.script_file_content, disabled: true}]
            })
          );
          this.workflowAddForm = this.formBuilder.group({
            workflow_name: [{value: this.scriptRunnerData.workflow_name, disabled: true}],
            runnerNodes: this.formBuilder.array(controls),
            executer_command: [{value: this.scriptRunnerData.executer_command, disabled: true}],
            config_name: [{value: this.scriptRunnerData.config_name, disabled: true}],
            config_file_content: [{value: this.scriptRunnerData.config_file_content, disabled: true}]
          });
        }
      }
    

    Now it is working as expected.