ngFor shows empty items after array.push
Asked Answered
H

1

12

I have this in my template:

<input type="button" value="add" (click)="addEnvVar()"/>
<div *ngFor="let envVar of application.env_vars">
    <input type="text" name="key" [(ngModel)]="envVar.key">
    <input type="text" name="value" [(ngModel)]="envVar.value">
</div>

The code behind addEnvVar(): this.application.env_vars.push({key:'', value:''});

When the component is initialized, there is one object inside env_vars and it is rendered just fine (the <input> fields are populated). After I click 'add', I can see in console that there are indeed two objects inside env_vars (the second is the 'empty' object I just added), and in the view there are indeed two <div>s for each envVar, but all 4 <input> fields are empty.

What am I doing wrong?

UPDATE

I think the problem is that when ngFor produces more than one div, the inputs in each div all get the same hard-coded name attribute (in my case - "key" and "value"), and the value is somehow attached to that. I changed name="key" to name="key_{{i}}" (i is a template variable holding the ngFor index property).

Question is, is this the way to go? Or am I still missing something?

Heffron answered 31/10, 2016 at 10:37 Comment(4)
Aren't you pushing empty values with {key:'', value:''} ? Then it makes sense nothing shows in the input field, since the model behind is also emptyLungki
@Lungki After adding, I have 4 input fields. The two new input fields should be empty, but the first two should still be populated with the values of the the first object in the array which hasn't changed.Heffron
This is a case where you should probably use reactive forms rather than model-based forms, and use a FormArray.Chas
Minimal example: plnkr.co/edit/z4JbCTk1WQdcYprXfUu2?p=previewChas
R
4

The culprit with errors like this is mostly likely the default trackBy function which tracks the references. Even if the data hasn't changed, but the references change, it will tear down the DOM and re-build it, meaning all data inside the input fields will be cleared.

Component

trackBy(index) { return index }

Template

*ngFor="let envVar of application.env_vars; trackBy: trackBy"

Unfortunately I cannot test it without a reproduction. However, JB Nizet's comment is right and you should follow this advice; this is a task more suited for reactive forms, and not template forms.

Ryley answered 30/8, 2017 at 0:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.