two-way binding arrays in angular 2
Asked Answered
P

3

9

I'm aware with basic 2-way binding in angular 2 as shown in the docs.

I have an array of persons, which I'm using to build an html list:

Now, when I click on a person's row, I can edit it using 2-way binding:

 <form>
    <label>Name: </label>
    <input [(ngModel)]="selectedPerson.name" name="name"/>

    <label>Description: </label>
    <input [(ngModel)]="selectedPerson.job" name="job"/>
</form>

Now, what I want is to 2-way bind the list itself: (The list is in a different view than the row editor)

 <div class='row' *ngFor="let person of model">
    <div class='col'>{{person.name}}</div>
    <div class='col'>{{person.job}}</div>
 </div>

Currently, I'm using *ngFor to list out all persons. If my model is an array of two persons, I get two rows. There are cases when the model might change to have 3 or 4 persons. Is there any way I can make angular detect this and add rows accordingly? [(ngModel)] doesn't seem to be applicable here.

Basically, I want my list view to update without having to refresh the page. How to I make the model used in ngFor listen to changes?

Pseudaxis answered 3/10, 2016 at 13:7 Comment(1)
Are you trying to share your model with another component or is the 'list' in the same component definition as your row editor?Kelwin
S
4

Thanks to @David Blaney. I am not sure if I can post it. I only wanted to extend your example to edit grid / edit table with two-way binding array directly on every row in the table - angular is taking care of updating the Array as user is writing in the "input element directly in the table". User can quickly edit the elements without first selecting the row in the table. In the original example of @David Blaney in the plunker I just replaced the whole table element in app/editor.component.ts with this:

<form id="bigForm">
  <table>
    <tr class='row'>
        <th class='col'>Name</th>
        <th class='col'>Job</th>
    </tr>
    <tr class='row' *ngFor="let person of model; let i = index" (click)="selectPerson(person)" >
      <td class='col'>
        <input [id]="'person.name' + i" [(ngModel)]="person.name" [name]="'person.name' + i"/>
        - {{person.name}}
      </td>
      <td class='col'>{{person.job}}</td>
    </tr>
  </table>
</form>

Then I can post several changed rows to the http server in one request.

Swinton answered 28/9, 2017 at 1:20 Comment(2)
Thanks for answering. +1. I'll try it out when I can.Pseudaxis
This was the solution I was hoping for. For others who are looking to use data binding with the same component's template, [(ngModel)] works the best.Limitation
K
3

Here is a plunker of an example of how you can bind your model variable to another component:

https://plnkr.co/edit/tM20HcUIx13ZUPh0faTB?p=preview

I have created a simple list component from your code above:

import { Component, Input  } from '@angular/core';

import { Person } from './person';

@Component({
  selector: 'my-list',
  template:`
    <h3>The List</h3>
    <tr class='row' *ngFor="let person of model">
      <td class='col'>{{person.name}}</td>
      <td class='col'>{{person.job}}</td>
    </tr>
})

export class List {
  @Input() model:Array<Person>;  
}

The Input decorator lets the component know to expect and input of this type and to use it in the scope of this component.

In the template of the editor component I have used the my-list directive and set the model input of the directive to the model in the editor component.

<my-list [model]="model" ></my-list>

This now lets any changes to the model be reflected int he child list component.

If you were wanting you notify a component that was not a child of the editor component you would need to use the @Output decorator and set up an EventEmitter that a listener can be bound to and then used to updated the list elsewhere.

Take a look at the documentation here:

https://angular.io/docs/ts/latest/cookbook/component-communication.html

Kelwin answered 3/10, 2016 at 15:17 Comment(2)
Thanks for answering. I'll try it and let you know. +1Pseudaxis
Thanks buddy. This example plnkr.co/edit/tM20HcUIx13ZUPh0faTB?p=preview help me.Tenuis
C
1

You dont want to do anything to watch on the array change. Angular takes care.

Here is the working example for your problem. ngFor example

Chloropicrin answered 3/10, 2016 at 13:49 Comment(2)
Thanks for answering. I'll try it and let you know. +1.Pseudaxis
The sample code from Angular does indeed do two way binding for an array, but it doesn't demonstrate whether it can do it at the array element level.Knocker

© 2022 - 2024 — McMap. All rights reserved.