Home > Mobile >  Angular Error: Cannot find control with path 'instructions -> 1 ->action'
Angular Error: Cannot find control with path 'instructions -> 1 ->action'

Time:09-06

I'm trying to build a form. This form has the below structure. My users need to be able to create any amount of entries for the instruction fields.

...
  this.buttonForm = this.fb.group({
    instructions: this.fb.array([
        this.fb.group({
            action: this.fb.control('', Validators.required),
            data: this.fb.group({
                message: this.fb.control(""),
                mediaName: this.fb.control(""),
                mediaType: this.fb.control(""),
                commandName: this.fb.control(""),
                commandTrigger: this.fb.control("")
            })
        })
    ]),
    name: this.fb.control("", Validators.required),
    dimensions: this.fb.group({
        width: this.fb.control(5, [Validators.required, Validators.min(1)]),
        height: this.fb.control(5, [Validators.required, Validators.min(1)]),
        positionX: this.fb.control(5, [Validators.required, Validators.min(0)]),
        positionY: this.fb.control(5, [Validators.required, Validators.min(0)])
    })
});

}

...

get instructionAray() {
    return this.buttonForm.get("instructions") as FormArray;
}

public addInstruction() {
    this.instructionAray.push(this.fb.control(""));
}

Below is the HTML for the component (excluding the non array items).

<ng-container formArrayName="instructions">
            <ng-container *ngFor="let instruction of instructionAray.controls; let i = index" [formGroupName]="i">
                <div >
                    <select #action  formControlName="action" 
                        (change)="resetInstruction(i, $event.target)">
                        <option value="Command">Command</option>
                        <option value="Media">Media</option>
                        <option value="Message">Message</option>
                    </select>
                    <div *ngIf="action.value == 'Message'" >
                        <div  formGroupName="data">
                            <p>Message:</p>
                            <input type="text" formControlName="message" >
                        </div>
                    </div>
                    <div *ngIf="action.value == 'Media'" formGroupName="data">
                        <div >
                            <p>Media:</p>
                            <input type="text" formControlName="mediaName" >

                        </div>
                        <div >
                            <p>Type:</p>
                            <select formControlName="mediaType" >
                                <option value="soundEffect">Sound Effect</option>
                                <option value="imageGif">Image / GIF / Static</option>
                                <option value="video">Video</option>
                            </select>
                        </div>
                    </div>
                    <div *ngIf="action.value == 'Command'" formGroupName='data'>
                        <div >
                            <p>Name:</p>
                            <input type="text" formControlName="commandName" >
                        </div>

                        <div >
                            <p>Trigger:</p>
                            <select formControlName="commandTrigger" >
                                <option selected value="Manual">Manual (Default, only option)</option>
                            </select>
                        </div>
                    </div>

                    <button (click)="delete(i)" >Delete Instruction</button>
                </div>
            </ng-container>
        </ng-container>

        <button (click)="addInstruction()" >
            Add Instruction</button>

I'm running into a problem when I try to display the form array data. The first item in the array with the defualt properties displays fine. However, when I add another item to the form array it fails with the below error.

ERROR Error: Cannot find control with path: 'instructions -> 1 -> action'
    Angular 11
    ButtonFormComponent_ng_container_40_Template button-form.component.html:68
    Angular 26
    RxJS 6
    Angular 23
    ButtonFormComponent_Template button-form.component.html:108
    Angular 12
    BoardComponent_ng_template_3_Template board.component.html:43
    Angular 8
    openTemplateSheetMenu board.component.ts:52
    BoardComponent_div_2_Template__svg_svg_click_1_listener board.component.html:23
    Angular 24
    BoardComponent_div_2_Template board.component.html:23
    Angular 9
    BoardComponent_Template board.component.html:20
    Angular 2
core.mjs:6412:22

I've been stuck on this for a few days now with no success.

CodePudding user response:

You need to push a FormGroup inside the FormArray instead of FormControl.

like this

public addInstruction() {
    this.instructionAray.push(
      this.fb.group({
        action: this.fb.control('', Validators.required),
        data: this.fb.group({
          message: this.fb.control(''),
          mediaName: this.fb.control(''),
          mediaType: this.fb.control(''),
          commandName: this.fb.control(''),
          commandTrigger: this.fb.control(''),
        }),
      })
    );
  }

You should also use the entire html content inside a form tag with the formGroup. like this.

<form [formGroup]="buttonForm">
  ....
  ....
</form>

CodePudding user response:

Translating this error to plain English;

You are creating a formArray and you are supplying a default object formGroup to it OnInit. At this point of time you created a formGroup by default inside your formArray. So in your array you have an object at index 0. Thus, when you press the addInstruction() you are pushing a new object to the array. Meaning an object at index 1. That's why the compiler complains about the absence of a control named action at index 1 when you push the new object by pressing addInstruction(). In the supplied code above, the addInstruction() does not create a new object that includes the shape of the object you set by default at index 0. It only pushes an abstract formControl to the formArray.

So you need to refactor as follows:

1- Declare a property in your class of type FormArray named instructions

public instructions: FormArray

2- Rework the addInstruction():

addInstruction() {
    this.instructions = this.buttonForm.get("instructions") as FormArray;
    this.instructions.push(this.createInstructions());
}

3- add a new method named createInstructions()

createInstructions(){
   return this.fb.group({
           action: this.fb.control('', Validators.required),
            data: this.fb.group({
                message: this.fb.control(""),
                mediaName: this.fb.control(""),
                mediaType: this.fb.control(""),
                commandName: this.fb.control(""),
                commandTrigger: this.fb.control("")
            })
})}

4- Remove the get instructionAray()

It is not recommended to call methods that way in your template. For performance reasons use direct properties. Knowing that you have the buttonForm already in your HTML you can access your formArray in the *ngFor as follows:

this.buttonForm.get('instructions')['controls']
  • Related