1

I'm trying to build a simple app with angular2, I have the below component:

@Component({
    selector: 'map-menu',
    templateUrl: './angular-app/components/map-menu.html'
})
export class MapMenuComponent {
    @Input() selectedMarkers: Array<google.maps.Marker>;
    constructor() {
    //      setInterval(() => {
    //          console.log(this);
    //      }, 1000);
        }
    }

when my map-menu.html is:

<ul class="nav nav-sidebar">
    <li *ngFor="#marker of selectedMarkers #i = index"><a href="#">{{marker.data.name}}</a></li>
</ul>

and in my app html I have:

<map-menu [selectedMarkers]="selectedMarkers"></map-menu>

and the list is not being updated, BUT when I'm adding the commented setInterval it is working fine. what am I missing there?

I've created a plunker with the solution

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
DiSol
  • 414
  • 2
  • 11

1 Answers1

4

From the User Input dev guide:

Angular only updates the bindings (and therefore the screen) if we do something in response to asynchronous events such as keystrokes.

I'm guessing you don't have an asynchronous event when the markers array is updated, hence nothing is causing Angular to run its change detection algorithm.

Update: The issue was not that there wasn't an asynchronous event, the issue was that the asynchronous event (google.maps.Marker.addListener()) is not known by Angular, hence Zone does not monkey patch it, hence Angular doesn't run its change detection algorithm when the data changes. The solution is to emit the event inside Zone's run() function:

marker.addListener('click', () => {
   this.zone.run(() => {
      this.markerClickEvent.next({data:{name: 'another'}});
   });
});

This will cause Angular to run its change detection algorithm, notice the change, and update the view.

The reason setInterval() works is because it is monkey patched by Zone.

See DiSol's plunker for more details.
If you want to learn more about Zone, watch Miško's video.
See also NgZone API doc.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • actually this array is being changed on click events so it is being updated with an event. – DiSol Dec 20 '15 at 07:17
  • @DiSol, here's a [working Plunker](http://plnkr.co/edit/JnAr2Go0X7XDI8NQwLiu?p=preview). Please let us know what is different in your code. – Mark Rajcok Dec 21 '15 at 15:08
  • I've modified it to be like the one in my app [edited plunker](http://plnkr.co/edit/wz8on0?p=info) and it seems to work, the only diff that there is between the plunker and my app is that in my app it is a google map with a marker and the click event is attached to the marker. I'll try to put it in the plunker as well in the near future. – DiSol Dec 21 '15 at 18:56
  • @DiSol, see if this SO question helps you: http://stackoverflow.com/questions/31352397/how-to-update-view-after-change-in-angular2-after-google-event-listener-fired – Mark Rajcok Dec 21 '15 at 19:16
  • Indeed invoking NgZone.run solved it and it is now working. Thanks a lot for the help. I guess events in google maps are not being considered as async events by Angular2.. – DiSol Dec 21 '15 at 19:53
  • @DiSol, can you update your plunker with NgZone working? I think it will be helpful for others to see. – Mark Rajcok Dec 21 '15 at 20:10
  • 1
    Done - you can take a look – DiSol Dec 21 '15 at 20:44