Creating child components in angular2 using NgFor does not work

I am using angular2 alpha 37.

I defined the <map> component and the <marker> component (a child of <map> ). The <map> component has an array data element that contains a list of marker coordinates. The <map> view should display all the markers in the array

When defining a <map> view as follows (explicitly listing the components for all members of the array):

 @View({ template:` <marker [model]="markers[0]"></marker> <marker [model]="markers[1]"></marker> `, directives:[Marker] }) 

<marker> components are updated every time the corresponding member of the array changes. This is the desired behavior.

When defining a <map> view as follows (using NgFor ):

 @View({ template: '<marker *ng-for="#m of markers" [model]="m"></marker>', directives:[Marker,NgFor] }) 

a new marker is created whenever the members of the array change, which is undesirable.

Needle to say that I would like to use the NgFor method.

I do not know what's happening. How can I use NgFor but avoid creating new <marker> instances each time I update individual tokens?

+6
source share
3 answers

Split the ngFor iteration list from model data.

This is a Dart code, but it is difficult to translate it to TS

 import 'dart:math' show Random; import 'package:angular2/angular2.dart'; @Component( selector: 'app-element', template: ''' <h3>app-element</h3> <map></map> ''', directives: const [MapComponent]) class AppElement {} 
 @Component(selector: 'map', template: ''' <button (click)="changeValue()">Change value</button> <marker *ngFor="let m of markersIndexes" [model]="markers[m]"></marker> <!-- use `markers[m]` to assign a model but `markersIndexes` for `*ng-for` --> ''', directives: const [MarkerComponent, NgFor]) class MapComponent { MapComponent() { markers = <Marker>[ new Marker('m0', 0), new Marker('m1', 1), new Marker('m2', 2), new Marker('m3', 3) ]; markersIndexes = new List<int>.generate(markers.length, (int index) => index); } List<Marker> markers; // model to pass to <marker> List<int> markersIndexes; // indexes used by *ng-for // when markers are added or removed markersIndexes need to by updated of course // Update random marker item with random position value Random _rnd = new Random(); void changeValue() { int idx = _rnd.nextInt(3); markers[idx].position = _rnd.nextInt(100); } } 
 @Component( selector: 'marker', template: ''' <h3>marker</h3> <div>name: {{model.name}} pos: {{model.position}} created: {{createdAt}}</div> ''', styles: const [ ''' :host { display: block; border: 1px solid green; } ''' ]) class MarkerComponent implements OnInit { @Input() Marker model; String createdAt; MarkerComponent() { createdAt = new DateTime.now().toString(); } void ngOnInit() { print(model); } } 
 // Marker model class Marker { String name; int position; Marker(this.name, this.position); @override String toString() => 'Marker: $name - $position'; } 
+3
source

try it

 @View({ template:"<marker *ng-for="#m of markers" [model]="m">{{m}}</marker>", directives:[Marker,NgFor] }) 
0
source

I saw that you are using the alpha37 version, which remains the alpha version, and you might have some errors ... I have done several tests using beta0 version and it seems to work as expected. Therefore, I would recommend that you upgrade to this version ... We expect beta versions to be more stable; -)

Here is the code I used for my test:

  • Main component

     @Component({ selector: 'first-app', template: ` <map></map> `, directives: [ MapComponent ] }) export class AppComponent { } 
  • Marker data object

     class Marker { name: string; position: int; constructor(name, position) { this.name = name; this.position = position; } } 
  • Marker Component

     @Component({ selector: 'marker', template:` <div class="marker">Marker {{model.name}} <button (click)="update()">Update</button></div> `, directives:[MarkerComponent] }) export class MarkerComponent implements OnInit { @Input() model: Marker; constructor() { } ngOnInit() { } update() { this.model.name = this.model.name + 'a'; } } 
  • Map component

     @Component({ selector: 'map', template:` <marker *ngFor="#m of markers" [model]="m"></marker> <button (click)="update()">Update</button> `, directives:[MarkerComponent] }) export class MapComponent { constructor() { this.markers = [ new Marker('m0', 0), new Marker('m1', 1), new Marker('m2', 2), new Marker('m3', 3) ]; } update() { this.markers[1].name = 'm1a'; } } 

When I click on both update buttons, the name of the second marker is updated in the view and no additional <marker> element appears.

Edit

This may be a way to update an item in a list. Are you overriding it with a new instance or updating the attribute value for an existing instance in the list? In the first case, I think you can add a new item to the list.

 update() { this.markers[1]= new Marker('m1a', 1); } 

After performing some tests, this approach also works. No items have been added to the list.

Hope this helps you, Thierry

0
source

All Articles