【问题标题】:How could I call a Angular2 function from a Google Map infowindow?如何从 Google Map 信息窗口调用 Angular2 函数?
【发布时间】:2017-02-05 23:04:59
【问题描述】:

Google 地图以 javascript 方式集成,我想在信息窗口中调用 angular2 函数,如下面的代码。看看infoContent 的按钮。

for (i = 0; i < locations.length; i++) {

  let locLatLng = new google.maps.LatLng(locations[i].latitude, locations[i].longitude);
  let infoContent = '<button (click)="myFunction(' + locations[i].id + ')">Details ...</button>';

  marker = new google.maps.Marker({
    position: locLatLng,
    map: this.map
  });

  google.maps.event.addListener(marker, 'click', (function(marker, i) {
    return function() {
      infowindow.setContent(infoContent);
      infowindow.open(this.map, marker);
    };
  })(marker, i));

}

不幸的是,角度点击事件(click)="myFunction()" 做不到。一定有别的办法。如果有人能指出我正确的方向,我会非常高兴。提前致谢。

【问题讨论】:

  • 你的addListener()有什么问题?如果this.map 没有按预期工作,请参阅下面的答案。还有别的吗?一些错误信息,...?
  • 打开信息窗口工作正常。如果我将方式从 (click) 更改为 onclick 我会得到一个 Uncaught ReferenceError: myFunction is not defined,但 myFunction() 在一个角度组件内。
  • 我猜你应该使用事件委托。你也可以看看这个问题stackoverflow.com/questions/6378007/…

标签: javascript google-maps-api-3 angular google-maps-markers


【解决方案1】:

请尝试这个问题的完整解决方案。

var infowindow = new google.maps.InfoWindow({});

    for (i = 0; i < locations.length; i++) {

        let locLatLng = new google.maps.LatLng(locations[i].latitude, locations[i].longitude);
        let infoContent = '<div style="padding: 0.5em;">' +
            '<h5 id="lt" style="font-size: 12px">'+locations[i].id +'</h5>'+
            '<button id="btn" style="font-size: 8px;" >Click</button>'+
            '</div>'

        marker = new google.maps.Marker({
            position: locLatLng,
            map: this.map
        });

        google.maps.event.addListener(marker, 'click', (function(marker, i) {
            return function() {
                infowindow.setContent(infoContent);
                infowindow.open(this.map, marker);
            };
        })(marker, i));
    }

    infowindow.addListener('domready', () => {
        var val = document.getElementById('lt').innerHTML;
        document.getElementById("btn").addEventListener("click", () => {
            this.myFunction(val);
        });
    });

【讨论】:

  • 仅适用于信息窗口中的单击事件,不能用于多个信息窗口。
【解决方案2】:

这是我的解决方案。首先,我将 id 设置为信息窗口中的按钮。在那之后,我捕获了信息窗口的“domready”事件,这意味着:所有的 HTML 都已被浏览器接收并解析到现在可以操作的 DOM 树中。然后使用 getElementById 访问按钮并添加事件“点击”。在这里你可以调用你在ts文件中定义的函数。

const infoWindowContent = '<h6>' + community.typeOfCommunity + '</h6>' +
          '<p>' + community.address.name + ' ' + community.streetNumber + ', ' + community.city + '</p>' +
          '<p>Manager: ' + community.manager.fullName + '</p>' +
          '<button  id="infoWindowButton">More info</button>';
        const infoWindow = new google.maps.InfoWindow({
          content: infoWindowContent
        });

        marker.addListener('click', () => {
          infoWindow.open(this.map, marker);
        });

        infoWindow.addListener('domready', () => {
          document.getElementById("infoWindowButton").addEventListener("click", () => {
            this.myFunction();
          });
        });

【讨论】:

    【解决方案3】:

    我搜索了很多并找到了答案:

    你必须使用:$compile(htmlString)(scope)

    在你的例子中试试这个:

    var infoContent = '<button ng-click="myFunction(' + locations[i].id + ')">Details</button>';
    
    var scope = angular.element(document.getElementById('anyElementId')).scope();
    var compiled = $compile(htmlElement)(scope);
    

    然后使用:

    infowindow.setContent(compiled[0]);
    

    哇!

    【讨论】:

      【解决方案4】:

      您可以在根窗口中实例化对 ngZone 的引用并从 infoWindow 内部调用它。

      首先你需要在构造函数中访问 NgZone:

       constructor(public _ngZone: NgZone) {    }
      

      然后您可以根据您的代码在窗口、ngOnInit、构造函数或某处将指针设置回您的区域:

          window["angularComponentRef"] = { component: this, zone: this._ngZone };
      

      最后,您可以使用 zone.run 从 infoWindow 回调到您的 Angular 函数,如下所示:

          for (i = 0; i < locations.length; i++) {
              let locLatLng = new google.maps.LatLng(locations[i].latitude, locations[i].longitude);
              let infoContent: string = '<button onclick="window.angularComponentRef.zone.run(() => {window.angularComponentRef.component.myFunction(\'' + locations[i].id + '\');})">Details ...</button>';
      
              marker = new google.maps.Marker({
                  position: locLatLng,
                  map: this.map
              });
      
              google.maps.event.addListener(marker, 'click', (function (marker, i) {
                  return function () {
                      infowindow.setContent(infoContent);
                      infowindow.open(this.map, marker);
                  };
              })(marker, i));
      
          }
      

      并且您可以在需要时清理函数以避免污染窗口命名空间,例如在 ngOnDestroy 上:

       window["angularComponentRef"] = null;
      

      【讨论】:

      • 老兄!你摇滚!
      • 天哪,谢谢你的朋友!拯救了我的一天,呸!几个小时以来一直在为此苦苦挣扎。干杯?
      【解决方案5】:

      更新(来自评论)

      您可以使用ElementRefRenderer 来实现,但这不是问题。问题是获取按钮的引用(直接 DOM 元素引用或ElementRef)。您可以注入private elRef:ElementRef 并使用this.elRef.nativeElement.querySelector('infowindow button') 或类似名称,但如果您访问elRef.nativeElement,您将再次超出平台中立的范围,因为不应直接访问nativeElement,而是受到Renderer 的限制只能调用方法而永远不能得到返回的结果,你能做的只有这么多。

      我会使用Trigger event with infoWindow or InfoBox on click Google Map API V3 中所示的方法,然后检查event.target 是否单击了您感兴趣的元素。

      原创

      如果你想在事件处理程序中访问this.map,你应该使用箭头函数

        google.maps.event.addListener(marker, 'click', ((marker, i) => { // <<<===
          return () => { // <<<===
            infowindow.setContent(infoContent);
            infowindow.open(this.map, marker);
          };
        })(marker, i)
      

      否则this. 不会指向当前类实例

      【讨论】:

      • 感谢您的回复。不幸的是,这并不能解决我的问题。我用onclick而不是(click)尝试了js方式,但我只收到Uncaught ReferenceError: myFunction is not defined
      • 我错过了`let infoContent = '';. Angular2 doesn't process bindings added dynamically therefore this is not supposed to work. Only bindings added to component templates statically are processed by Angular2. You need to use addEventListener()` 用于动态添加的元素。
      • 感谢您指出正确的方向。 addEventListener() 的 angular2 方式似乎通过ElementRefRenderer。我试试看。
      • 是的,使用RendererElementRef 是平台中立的方式,但如果您使用GoogleMaps,那么您已经不在这个领域了,因此它不会给您带来太多好处。有关示例,请参阅stackoverflow.com/questions/12102598/…。因为setContent() 采用字符串,所以无法将事件处理程序添加到单个元素。我假设您可以从信息窗口本身的 click 事件中收到的 MouseEvent 获取实际元素。
      • 您可以使用ElementRefRenderer 来实现,但这不是问题。问题是获取按钮的引用(直接 DOM 元素引用或ElementRef)。您可以注入private elRef:ElementRef 并使用this.elRef.nativeElement.querySelector('infowindow button') 或类似名称,但如果您访问elRef.nativeElement,您将再次超出平台中立的范围,因为不应直接访问nativeElement,而是受到Renderer 的限制只能调用方法,但永远不能得到结果,你能做的只有这么多。
      猜你喜欢
      • 1970-01-01
      • 2018-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多