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>
)
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.
The above answers are solid, but you lose your binding on:
infowindow.setContent( compiled[0].innerHTML );
Do this instead:
infowindow.setContent( compiled[0] );
Otherwise if you have something like <div>{{myVar}}</div>
, it won't update if myVar
is updated in your app.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With