Google map is integrated the javascript way and I want to call a angular2 function inside an infowindow like the following code. Take a look at infoContent
for the
You can do the trick instancing a reference to ngZone in root Window and call it from inside the infoWindow.
First you need to get access to NgZone in constructor:
constructor(public _ngZone: NgZone) { }
And then you can set a pointer back to your zone in window, on ngOnInit, constructor or somewhere, depending of your code:
window["angularComponentRef"] = { component: this, zone: this._ngZone };
Finally you can callback from infoWindow to your Angular function with zone.run like this:
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));
}
And you can clean the function when needed to avoid polute the window namespace, on ngOnDestroy for example:
window["angularComponentRef"] = null;
Here is my solution. First, I set id to button in info window. After that, I caught 'domready' event for info window which means: all the HTML has been received and parsed by the browser into the DOM tree which can now be manipulated. And then with getElementById accessed to button and add event 'click'. Here you can call your function defined in ts file.
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();
});
});
update (from comment)
You can do it with ElementRef
and Renderer
but that is not the problem. The problem is to get a reference (direct DOM element reference or ElementRef
) of the button. You can inject private elRef:ElementRef
and use this.elRef.nativeElement.querySelector('infowindow button')
or similar but if you access elRef.nativeElement
you're out of the realm of platform neutrality again because nativeElement
should not be accessed directly, but with the limitation of the Renderer
of only being able to call methods but never to get a result in return, there is only so much you can do.
I would use a method like shown in Trigger event with infoWindow or InfoBox on click Google Map API V3 and then check the event.target
if an element you are interested in was clicked.
original
If you want to access this.map
in the event handler you should use arrow functions instead
google.maps.event.addListener(marker, 'click', ((marker, i) => { // <<<===
return () => { // <<<===
infowindow.setContent(infoContent);
infowindow.open(this.map, marker);
};
})(marker, i)
otherwise this.
won't point to the current class instance
Please try this complete solution for this question.
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);
});
});
I'm search a lot and found the answer:
You must use: $compile(htmlString)(scope)
In your example try this:
var infoContent = '<button ng-click="myFunction(' + locations[i].id + ')">Details</button>';
var scope = angular.element(document.getElementById('anyElementId')).scope();
var compiled = $compile(htmlElement)(scope);
And then use:
infowindow.setContent(compiled[0]);
Wala!