0

I'm working on a form on a page that can be repeated several times, essentially as many times as needed to create a list of similar data that is then saved. I'm using a FormArray to recreate the items each time. I've used FormArray before and not had any trouble but this time around when I add any of the form items that come after the first two the browser hangs and eventually crashes with the error "call stack exceeded".

Clearly it is trying to do sometime in a loop but I can't figure out what. The FormArray works on this page in principle as if I only have the first time items there isn't a problem. Only trying to add any more controls force the loop.

This is the code behind where I specify the controls in the array and add the first one, so the first set of controls appear on the page

form.ts:

this.sessionsForm = this.formBuilder.group({
        sessions: this.formBuilder.array([])
    });
    const sessions = this.sessionsForm.controls.sessions as FormArray;
    sessions.push(this.formBuilder.group({
        'session_id': [null],
        'title': [null, Validators.required],
        'tutor': [null, Validators.required],
        'date': [null, Validators.required],
        'hour': [null, Validators.compose([Validators.required, Validators.minLength(2), Validators.maxLength(2)])],
        'minute': [null, Validators.compose([Validators.required, Validators.minLength(2), Validators.maxLength(2)])],
        'meridiem': [null, Validators.required],
        'editor': [null],
        'editors': [null],
        'type': [null, Validators.required],
        'location': [null, Validators.required],
        'enabled': [null],
        'attendees': [null],
        'feature_image': [null],
        'duration': [null, Validators.required],
        'participants':[null],
        'learner_info': [null],
        'delivery_info':[null],
        'tutor_resources': [null],
        'is_template': [null, Validators.required]
    }));

form.html: Only the first two controls that work and then subsequent two are shown here for brevity. It doesn't matter which control I add after the first two, the loop happens. OK, that isn't completely true. Sometimes I can get another control to show but adding the fourth causes the loop but on other times the third control, which did work, then stops working again and I'm back to the looping crash.

<form [formGroup]="sessionsForm">
                    <div class="array_section" *ngIf="sessionsForm.controls.sessions">
                        <div class="array_item" formArrayName="sessions" *ngFor="let session of sessionsForm.controls.sessions?.value; let i = index">
                            <ng-container [formGroupName]="i">
                                <div class="left-container">
                                    <div class="wrapper"> 
                                        <div class="form__row">
                                            <div class="form__col">
                                                <div class="form__field">
                                                    <mat-form-field class="form__input">
                                                        <input matInput placeholder="Parent stream" value="{{parentStream.title}}" disabled>
                                                    </mat-form-field>
                                                </div>
                                            </div>
                                            <div class="form__col">
                                                <div class="form_field">
                                                    <mat-checkbox class="form__input" formControlName="is_template">Create a template</mat-checkbox>
                                                </div>
                                            </div> 
                                        </div> 

                                        <div class="form__row">
                                            <div class="form__col">
                                                <div class="form__field">
                                                    <mat-form-field class="form__input">
                                                        <input placeholder="Session Title" matInput formControlName="title" class="form__input">
                                                    </mat-form-field>
                                                </div>
                                            </div>
                                        </div>

                                        <!-- <div class="form__row">
                                            <div class="form__col">
                                                <div class="form__field">
                                                    <mat-form-field class="form__input">
                                                        <mat-select placeholder="Duration (minutes)" formControlName="duration">
                                                            <mat-option *ngFor="let duration of durations" value="{{ duration }}">{{ duration }}</mat-option>
                                                        </mat-select>
                                                    </mat-form-field>
                                                </div>
                                            </div>
                                            <div class="form__col">
                                                <div class="form__field">
                                                    <mat-form-field class="form__input">
                                                        <mat-select placeholder="Type" formControlName="type">
                                                            <mat-option *ngFor="let type of types" value="{{ type }}">{{ type }}</mat-option>
                                                        </mat-select>
                                                    </mat-form-field>
                                                </div>
                                            </div>
                                        </div> -->

If anyone has any advice on what could be the cause I'd love to hear it, this has stumped me for a while now.

Thanks.

3
  • 1
    Do you have a simple stackblitz that can reproduce this? It is hard to see everything that could be going on. It does appear that you should be using *ngFor="let session of sessionsForm.controls.sessions.controls; let i = index" for your ngFor Commented Oct 10, 2019 at 21:45
  • 1
    You have an *ngFor repeating the formArrayName="sessions"directive. There is a single form array in your form. It shouldn't be repeated. Commented Oct 10, 2019 at 21:50
  • @observingstream, well spotted and you are correct. That sorted it. If you put that as answer I'll mark it for you. JB Nizet, good thought, I tried that first but it didn't solve the problem. Thank you both! Commented Oct 10, 2019 at 22:02

1 Answer 1

1

When you use form arrays in Angular, in your template, you need to reference the controls property vs the value. It is not completely clear what is causing the endless loop in your code, but when you reference the value, if something causes the value to change, that causes your loop to be rendered again. If the thing that causes the value to change is part of the setup, then Angular change detection would continually run until it ran out of the call stack.

See https://stackblitz.com/edit/angular-zezvfy and https://angular.io/guide/reactive-forms#step-4-displaying-the-form-array-in-the-template

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.