AngularJS ng-include 在 Google Maps InfoWindow 中? [英] AngularJS ng-include inside of Google Maps InfoWindow?

查看:31
本文介绍了AngularJS ng-include 在 Google Maps InfoWindow 中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将模板文件 views/infowindow.html 作为我的 InfoWindow 内容包含在我编写的用于启动 google maps api 的服务中:

for ( var count = location.length, i = 0; i < count; i++ ) {var latLng = 位置 [i],标记 = 新的 google.maps.Marker({…}),infowindow = new google.maps.InfoWindow();google.maps.event.addListener(标记,'点击',(功能(标记,latLng){返回函数(){var content = '<div ng-include src="\'infowindow.html\'"></div>';infowindow.setContent( 内容 );infowindow.open( 地图, 标记);}//返回fn()})( 标记 , latLng ));//添加监听器}//为了

然而,似乎 Angular 在插入 InfoWindow 时没有处理 content(当通过 Dev Tools 检查代码时,插入的代码是 <div ng-包括 src="'views/infowindow.html'"></div>).

我希望 Angular 在插入到 InfoWindow 之前对我的包含进行预处理,但可惜没有.

我正在尝试做的事情可行吗?

我想在将模板传递给 infowindow.setContent() 之前我必须以某种方式缓存模板,但我不知道如何做到这一点(或者如果那是什我应该这样做).我更愿意在事件上加载模板,而不是为每个标记缓存和注入它.

编辑查看 $templateCache 和一个相关的 SO 问题.

EDIT 2 这是一个尝试使用 plunk$compile (InfoWindow的内容还是<div id="infowindow_content" ng-include src="'infowindow.html'"></div>)


解决方案

这个基础来自马克在下面的回答.在他的解决方案中,InfoWindow 的内容是在第一次点击(任何标记)时编译的,但直到再次点击任何标记时,InfoWindow 才会真正打开,这可能是因为 GoogleMaps 不耐烦.

$compile 移到外面,然后将编译好的模板传入 .addListener 解决了这个问题:

for ( … ) {…infowindow = new google.maps.InfoWindow();范围.标记…var content = '<div id="infowindow_content" ng-include src="\'infowindow.html\'"></div>';var 编译 = $compile(content)(scope);google.maps.event.addListener(标记,'点击',(功能(标记,范围,编译,localLatLng){返回函数(){scope.latLng = localLatLng;//使数据可用于模板scope.$apply();//必须在里面为每个标记写新值infowindow.setContent(已编译[0].innerHTML);infowindow.open( 地图, 标记);};//返回fn()})( 标记、作用域、编译、作用域.markers[i].locations));//添加监听器}//为了

更新的 Plunker.

解决方案

在你把 content 添加到 DOM 之后,你需要找到它(也许用 jQquery 选择器?),然后$compile() 并将其应用于适当的范围.这将导致 Angular 解析您的内容并根据它找到的任何指令(如 ng-include)采取行动.

例如,$compile(foundElement)(scope)

没有更多的代码,很难给出更准确的答案.不过,这里有一个类似的问题和答案,你可以看看.

更新:好的,我终于开始使用它了,我学到了一些东西.

google.maps.event.addListener(标记,'点击',(功能(标记,范围,localLatLng){返回函数(){var content = '<div id="infowindow_content" ng-include src="\'infowindow.html\'"></div>';scope.latLng = localLatLng;var 编译 = $compile(content)(scope);范围.$应用();infowindow.setContent(已编译[0].innerHTML);infowindow.open( 地图, 标记);};//返回fn()})( 标记,范围,范围.markers[i].locations )

我的印象是只有 DOM 元素可以被 $compiled——也就是说,我首先必须将内容添加到 DOM,然后再编译它.事实证明,事实并非如此.上面,我首先针对 scope 编译 content,然后将其添加到 DOM.(我不知道这是否会破坏数据绑定——即由 $compile 设置的 $watch()es.)我必须设置 scope.latLng 因为 ng-included 模板需要插入 {{latLng[0]}}{{latLng[1]}}.我使用 innerHTML 而不是 outerHTML 以便只插入 infowindow.html 的内容.

Plunker.

Update2: 第一次点击无效.看来'infowindow.html'直到第二次点击才被加载(我尝试第二次调用scope.$apply()...没有帮助).当我让 plunker 工作时,我已经在 index.html 中内联了 infowindow.html 的内容:

我在 addListener() 中使用了它:

var content = '<div id="infowindow_content" ng-include src="\'/test.html\'"></div>';

我将 plunker 更改为使用内联模板.

I'm trying to include a template file views/infowindow.html as the content of my InfoWindow from service I wrote to initiate the google maps api:

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

  var latLng  = locations[i],
    marker = new google.maps.Marker({
      …
    }),
    infowindow = new google.maps.InfoWindow();

  google.maps.event.addListener(
    marker,
    'click',
    (function( marker , latLng ){
      return function(){
        var content = '<div ng-include src="\'infowindow.html\'"></div>';
        infowindow.setContent( content );
        infowindow.open( Map , marker );
      }//return fn()
    })( marker , latLng )
  );//addListener

}//for

However, it seems that Angular is not processing content when it is inserted into the InfoWindow (when inspecting the code via Dev Tools, the code that gets inserted is <div ng-include src="'views/infowindow.html'"></div>).

I was hoping Angular would pre-process my include before it was inserted into the InfoWindow, but alas no.

Is what I'm trying to do possible?

I'm thinking that I'll have to somehow cache the template before passing it to infowindow.setContent(), but I don't know how to do that (or if that's even what I should be doing). I would prefer to load the template on the event instead of caching and injecting it for each marker.

EDIT Looking at $templateCache and a related SO question.

EDIT 2 Here's a plunk that tries to use $compile (the content of InfoWindow is still <div id="infowindow_content" ng-include src="'infowindow.html'"></div>)


SOLUTION

The basis for this came from Mark's answer below. In his solution, the content for InfoWindow is compiled on first click (of any marker) but the InfoWindow does not actually open until another click on any Marker, probably because GoogleMaps is impatient.

Moving the $compile outside and then passing the compiled template into .addListener solves this problem:

for ( … ) {
  …
  infowindow = new google.maps.InfoWindow();
  scope.markers …
  var content = '<div id="infowindow_content" ng-include src="\'infowindow.html\'"></div>';
  var compiled = $compile(content)(scope);

  google.maps.event.addListener(
    marker,
    'click',
    (function( marker , scope, compiled , localLatLng ){
      return function(){
        scope.latLng = localLatLng;//to make data available to template
        scope.$apply();//must be inside write new values for each marker
        infowindow.setContent( compiled[0].innerHTML );
        infowindow.open( Map , marker );
      };//return fn()
    })( marker , scope, compiled , scope.markers[i].locations )
  );//addListener

}//for

Updated Plunker.

解决方案

After you add the content to the DOM, you'll need to find it (maybe with a jQquery selector?), then $compile() it and apply it to the appropriate scope. This will cause Angular to parse your content and act on any directives it finds (like ng-include).

E.g., $compile(foundElement)(scope)

Without more code, it is difficult to give a more precise answer. However, here is a similar question and answer you can look at.

Update: okay, I finally got this to work, and I learned a few things.

google.maps.event.addListener(
      marker,
      'click',
      (function( marker , scope, localLatLng ){
        return function(){
          var content = '<div id="infowindow_content" ng-include src="\'infowindow.html\'"></div>';
          scope.latLng = localLatLng;
          var compiled = $compile(content)(scope);
          scope.$apply();
          infowindow.setContent( compiled[0].innerHTML );
          infowindow.open( Map , marker );
        };//return fn()
      })( marker , scope, scope.markers[i].locations )

I was under the impression that only DOM elements could be $compiled -- i.e., that I first had to add the content to the DOM, and then compile it. It turns out that is not true. Above, I first compile content against the scope, and then add it to the DOM. (I don't know if this might break databinding -- i.e., the $watch()es that were set up by $compile.) I had to set scope.latLng because the ng-included template needs to interpolate {{latLng[0]}} and {{latLng[1]}}. I used innerHTML instead of outerHTML so that only the contents of infowindow.html are inserted.

Plunker.

Update2: Clicking does not work the first time. It appears that 'infowindow.html' is not loaded until a second click (I tried calling scope.$apply() a second time... didn't help). When I had the plunker working, I had inlined the contents of infowindow.html in index.html:

<script type="text/ng-template" id="/test.html">
  <h4>{{latLng[0]}},{{latLng[1]}}</h4>
</script>

I was using that in addListener():

var content = '<div id="infowindow_content" ng-include src="\'/test.html\'"></div>';

I changed the plunker to use the inlined template.

这篇关于AngularJS ng-include 在 Google Maps InfoWindow 中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆