AngularJS ng-include 在 Google Maps InfoWindow 中? [英] AngularJS ng-include inside of 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));//添加监听器}//为了
在你把 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 的内容.
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
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.
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屋!