2

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>
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
SquishyAura
  • 43
  • 2
  • 8

1 Answers1

7

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

Community
  • 1
  • 1
yurzui
  • 205,937
  • 32
  • 433
  • 399
  • Thanks for your solution, it's leading me to the right path. this.myForm.get('questions.0.answers') works almost as intended, however do you perhaps know a way to add an answer to the respective question? Because no matter at which question I decide to add an answer, only the first question recieves a gets added a new answer, hence the "question.0.answers". I've just added my HTML on the post :) – SquishyAura Mar 26 '17 at 16:23
  • You my good sir are a saviour. Thanks a ton and have a wonderful day! – SquishyAura Mar 26 '17 at 16:35