Angular2 - ngZone - google.maps 不触发变化检测

Angular2 - ngZone - google.maps doesn't trigger change detection

我正在使用 Geocoder API,当返回结果时,双向数据绑定不起作用。数据只是不在视图内刷新。如果我手动更改任何其他 属性,数据就会刷新...因此,我搜索(很多)并找到了使用 ngZone 的解决方案。这是我所做的:

  getLocation(address: string): void {
    var mygc = new google.maps.Geocoder();
    this._ngZone.runOutsideAngular(() => {

      mygc.geocode({
        'address': address
      }, (results, status) => {

        var data: any = results[0];

        this._ngZone.run(() => {
          this.myObject.myData = {          
            lat: data.geometry.location.lat(),
            lng: data.geometry.location.lng()
          };
        });

      });

    });
  }

所以我有几个问题:

  1. 什么时候使用 ngZone?文档相当松散...
  2. 既然这在没有 runOutsideAngular() 的情况下也有效,那么使用它有什么意义呢?该示例也包括此函数调用,因此我也实现了它。但是没有它也可以工作...
  3. 有没有其他方法可以在视图中刷新 myObject

谢谢!

如果我错了,有人会开枪打我,但据我所知,如果在 zone.js 加载后下载外部脚本,则需要使用它。这意味着该脚本内的任何更改都不会被更改检测检测到。这是稍后加载 google 地图时发生的情况。也许……

无论如何,如果是这种情况,那么您必须使用 ngZone.run 方法。

如果你想运行手动改变检测之外的东西,所以如果你想强制不触发它,你应该使用runOutsideAngular。这不是您的 use-case,因此您可以安全地删除它。

The most common use of this service is to optimize performance when starting a work consisting of one or more asynchronous tasks that don't require UI updates or error handling to be handled by Angular. Such tasks can be kicked off via runOutsideAngular and if needed, these tasks can reenter the Angular zone via run.

但另一方面,您提到双向数据绑定对您不起作用 (ngModel)。我认为真正的问题是您在现有对象上更新 属性。这本身不会触发双向变化检测,并且是 ngZone.run 起作用的实际原因。如果是这种情况,那么 changeRef.detectChanges 将不起作用,您最好使用 ApplicationRef 并执行 tick()。或者不使用 two-way 数据绑定并使用 data goes down, events go up 模式。

constructor(private appRef: ApplicationRef){}

getLocation(address: string): void {
  let mygc = new google.maps.Geocoder();

  mygc.geocode({
    'address': address
  }, (results, status) => {

      let data: any = results[0];

      this.myObject.myData = {          
         lat: data.geometry.location.lat(),
         lng: data.geometry.location.lng()
      };

      this.appRef.tick();
  });
}

这显然有效,因为它与 ngZone.run 没有什么不同。但未触发更改检测的主要原因是 google.maps 使用其自己的一组 events/addEventListener 调用。这些事件 - 不是 - 由 zone.js 修补的所谓猴子,因此不会 运行 在 Angular 区域中,这在逻辑上不会触发更改检测周期。

因此,您可以使用 ngZone.run 选项或 ApplicationRef.tick 来解决此问题。我认为 ngZone.run 最有意义,因为它允许您(重新)进入 angular 区域,这正是您想要的。

如需 'good' 阅读有关 NgZone 的内容,您可以查看 api

我简单地使用:

  import { NgZone } from '@angular/core';

  constructor(
    private zone: NgZone
  ) { super(); }


 getLocation(address: string): void {
  var mygc = new google.maps.Geocoder();
  var self = this;

  mygc.geocode({
    'address': address
  }, (results, status) => {

    var data: any = results[0];

    self.zone.run(() => {
      self.myObject.myData = {          
        lat: data.geometry.location.lat(),
        lng: data.geometry.location.lng()
      };
    });
});