SquishyAura
SquishyAura

Reputation: 43

Angular 2 - Accessing Nested Formarrays (FormBuilder)

I'm using Angular 2 ReactiveForms to create a form. The form consists of a template, questions & answers. A template contains many questions, and questions contain many answers.

ngOnInit() {
    // initialize template
    this.myForm = this.formBuilder.group({
        title: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(30)]],
        owner: [localStorage.getItem('user')],
        questions: this.formBuilder.array([
            this.initQuestion()
        ])
    }); 
}

initQuestion() {
    // initialize question
    return this.formBuilder.group({
        questionText: [{value: '', disabled: true}],
        answers: this.formBuilder.array([
            this.initAnswer()
        ])
    });
}

initAnswer() {
    // initialize answer
    return this.formBuilder.group({
        answerText: [{value: '', disabled: true}]
    });
}

addQuestion() {
    const control = <FormArray>this.myForm.controls['questions'];
    console.log(control);
    control.push(this.initQuestion());
}

addAnswer() {
    const control = <FormArray>this.myForm.get(['questions.0.answers']);
    control.push(this.initAnswer());
}

My goal is to allow the user to add questions to the template, and answers to each question. My issue however is that I'm having trouble accessing the nested array called "answers". As of now, I'm able to add questions and it works fine, but the moment I try to add answers to questions (the addAnswer() method), I get an error that says "Cannot read property 'push' of null", which is referencing the control.push in addAnswer() method. Any help is appreciated!

Edit: forgot to add my HTML code:

<table class=pageTable align=center border="1px">
    <form [formGroup]="myForm" novalidate (ngSubmit)="save(myForm)" align=center>
        <!-- we will place our fields here -->
        <input type="submit" [disabled]="!myForm.valid" value="Submit Template">

        <!-- Template Title -->
        <div class="form-group">
            <label>Template Title:</label><br/>
            <input type="text" formControlName="title"><br/>
            <!--display error message if name is not valid-->
            <small *ngIf="!myForm.controls.title.valid" class="text-danger">
                Title must be between 5-30 characters.
            </small>
        </div>

        <br/>

        <!-- List of Questions -->
        <div formArrayName="questions" align=center>
            <div [formGroupName]="i" *ngFor="let question of myForm.controls.questions.controls; let i=index" class="Question-panel">
                <div class="Question-panel-title">
                    <span>Question {{i + 1}}:</span>
                    <!-- show remove button when more than one address available -->
                    <span *ngIf="myForm.controls.questions.controls.length > 1"  
                        (click)="removeQuestion(i)">
                    </span>
                    <question [group]="myForm.controls.questions.controls[i]"></question>
                </div>

                <!-- Llist of Answers -->
                <div formArrayName="answers" align=center>
                    <div [formGroupName]="j" *ngFor="let answer of question.controls.answers.controls; let j=index">
                        <div class="Question-panel-content">
                            <span>Answer {{j + 1}}:</span>
                            <br/><a (click)="addAnswer()" style="cursor: default">
                                Add answer
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <br/>

        <a (click)="addQuestion()" style="cursor: default">
            Add question
        </a>
    </form>
</table>

Upvotes: 2

Views: 2798

Answers (1)

yurzui
yurzui

Reputation: 214047

I think you should use string

this.myForm.get('questions.0.answers')

or array like

this.myForm.get(['questions', 0, 'answers']);

Update

According to your html

addAnswer(idx: number) {
  const control = <FormArray>this.myForm.get(['questions', idx, 'answers']);
  control.push(this.initAnswer());
}

and in html

<a (click)="addAnswer(i)">Add answer</a>

See also

Upvotes: 7

Related Questions