AngularJS: 'google-maps': call directive in infoWindow - angularjs

I'm using http://nlaplante.github.io/angular-google-maps/ to display a map in my angular Application.
I have a general controller for my page getting a Json.
to display markers, i'm using $watch in the scope cause I will do real time and the markers positions can change.
$scope.model = new Model 'api/now.json'
$scope.state = new DState
$scope.$watch ->
markers = []
_($scope.model.objects).each (obj) ->
markers.push
latitude: obj.latitude
longitude: obj.longitude
infoWindow: "<info-window>SHOULD NOT DISPLAY CAUSE DIRECTIVE</info-window>"
markers
, (newValue) ->
$scope.state.map.markers = newValue
, true
My directive is basic:
am.directive "infoWindow", ->
restrict: 'E'
template: "<div>IN DIRECTIVE</div>"
replace: true
My Html page calling the map:
#dashboard{ng:{controller: 'dashboardCtrl'}}
#map.google-map{center: 'state.map.center',
zoom: 'state.map.zoom',
markers: 'state.map.markers',
draggable: 'true'}
And The DState Factory to define the state:
.factory 'DashboardState', (Media) ->
class DashboardState
defaults:
map:
center:
latitude: 45.764043
longitude: 4.835659
zoom: 10
markers: []
selectedObj: null
constructor: (initialData) ->
_(#defaults).extend initialData
_(this).extend #defaults
So, my display here in my infoWindow is
SHOULD NOT DISPLAY CAUSE DIRECTIVE
But I should have what is in my directive:
IN DIRECTIVE
My directive is not called ... Do you have an idea?
It's a double question here, I would like to set the SelectedObj of my factory to the Obj himself. Do you have an Idea how to handle the event click on marker and where to place it to call the method who could assign my obj to SelectedObj?
Thanks by advance

You can try the following:
get the latest version of angularjs-ui-maps
Use the tempalteUrl property of the directive - you can add your directives inside the template (see how this is done in the example.html that's included in the source).
This way you can avoid any custom compilation of html
I'd faced a similar problem: https://stackoverflow.com/questions/20843463/angularjs-using-a-directive-in-google-maps-marker-window
In case you find any other approach, please do post it.
HTH

Related

why to make directive in angularjs not renderning second time?

why my google directive not working ? Actually I make a simple directive of google map .And display on view.it work first time .But not work for second time .I will explain more When I run my plunker it show me Qutub minar google map.But when I click
‘+’ icon and press done button add another location example “Delhi” it give me longitude and latitute but not display the map
here is my code
Issue on this fuction I think
this.loadMap = function(latLng) {
console.log("function latlng called");
console.log(latLng);
google.maps.visualRefresh = true;
var myCenter = new google.maps.LatLng(latLng.latitude, latLng.longitude);
var map = new google.maps.Map(document.getElementById("id"), mapProp);
var marker = new google.maps.Marker({
position: myCenter,
});
marker.setMap(map);
}
You actually have two major troubles :
You generate multiple div with the same id (googleMap).
When you run the directive it get element by id but there is multiple elements with this ID which cause it to mess.
The main problem is that generating the google-map shouldn't be the responsibility of your "pane" directive but should be a totally new directive instead.
You can see it working in this plunker :
What i did :
I create a new directive myGoogleMap which basically use your old loadMap function (That i removed from the tabs directive). I also took the "latlng" attribute from the pane and put it on this directive.
.directive('myGoogleMap', function(){
return {
scope: {
latlng: '='
},
link: function(scope, element, attrs){
var latLng = scope.latlng;
console.log("function latlng called");
console.log(latLng);
google.maps.visualRefresh = true;
var myCenter;
myCenter=null;
myCenter = new google.maps.LatLng(latLng.latitude, latLng.longitude);
var mapProp = {
center: myCenter,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(element[0], mapProp);
var marker = new google.maps.Marker({
position: myCenter,
});
marker.setMap(map);
}
}
The main difference is that the directive that generate the google map is already on the good element. I'll be able to access this element with element[0] in the link function. That mean i can actually generate a google map everywhere else giving a latlng object and using this directive.
Now your ng-repeat for pane looks like this :
<div ng-repeat="tabInfo in tabPlaces.tabItems" pane title="{{ tabInfo.title}}" ng-show="tabInfo.selected">
<p>{{ tabInfo.content }}</p>
<div my-google-map latlng="tabInfo.latlng" ng-style="mapConfig" style="height:200px;width:100%"></div>
</div>
Hope it helped.

Angular UI Map Not Updating for Scope Changes

I am trying to update the Angular ui-map when the scope changes. I have added a $watch and I can see the scope change in console but the map is not updating with the change in latitude and longitude. This is what I have:
$scope.mapOptions = {
zoom: 4,
center: new google.maps.LatLng(-25.363882,131.044922),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var updateCenter = function() {
$scope.mapOptions = {
zoom: 11,
center: new google.maps.LatLng($scope.fromLat, $scope.fromLng),
};
console.log($scope.mapOptions);
}
$scope.$watch('fromLat', updateCenter);
$scope.$watch('fromLng', updateCenter);
Where the $scope.fromLat and $scope.fromLng are the scope changes that I am watching. When I log these scopes in console I can see the scopes updated. But the map is still on the initial state.
Okay, this is what I did to resolve this issue. I did 2 changes:
1) Used setCentre() in Controller:
In the updateCenter() method, instead of updating the $scope.mapOptions, I used setCenter() to directly change the map center.
var updateCenter = function() {
$scope.myMap.setCenter(new google.maps.LatLng($scope.fromLat, $scope.fromLng));
}
Here, myMap is the scope added to ui-map like this:
div ui-map="myMap" ui-options="mapOptions" class="google-map"></div>
2) ng-change in View or $watch:
Secondly, I added a $watch for updating the map instantly. There are 2 ways:
I can add ng-change attribute to the input scope that calls the above function when the latitude and longitudes scopes are changed. This way the map change is in effect immediately.
<input id="fromLat" type="text" ng-model="fromLat" ng-change="updateMap()" name="fromLat" />
Or add a $watch in controller:
$scope.$watch('fromLat', updateCenter);

Pass coordinates from service to directive with angular

I made a directive for my google maps on my angular application. The latitude and longtitude are hard coded in the directive. I'm trying to get those coordinates from my service just the same as I get the location name and description.
<h2 class="page-title">{{ locationInfo.name }}</h2>
<img ng-src="{{ locationInfo.images[0].scenic}}" alt="">
<p>{{ locationInfo.description }}</p>
<gmap id ="map-canvas" class="map"></gmap>
My directive is currently looking like this which gives a static map instead of changing dynamically
.directive("gmap", function () {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
link: function(scope, element, attrs) {
var latLng = new google.maps.LatLng(40, -73);
var mapOptions = {
zoom: 15,
center: latLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById(attrs.id), mapOptions);
var marker = new google.maps.Marker({
position: latLng,
map: map
});
}
}
});
First, instead of using document.getElementById you should make use of the "element" atribute which you inject in your link function. That "element" is your angular object corresponding to your DOM element. If you can't use it, then go ahead using document.getElementById, but change the "id" dynamically.
Also, if you want to use it as a directive I would suggest to use two attributes for your latitude and longitude, and naming your id dynamically using some property of your locationInfo object:
<gmap id ="map-canvas_{{locationInfo.name}}" lat="locationInfo.lat" lon="locationInfo.lon" class="map"></gmap>
where locationInfo contains latitude and longitude info named as lat and lon.
Then in your directive, you read your tag atritubes via the attrs object:
.directive("gmap", function () {
return {
...
// Here you read your tag attributes "lat" and "lon"
link: function(scope, element, attrs) {
var latLng = new google.maps.LatLng(attrs.lat, attrs.lon);
// Here you can use the injected "element" instead of "document.getElementById(attrs.id)" but it seems it doesn't work for you
var map = new google.maps.Map(document.getElementById(attrs.id), mapOptions);
}
}
});
Also I recomend to define your variables using comma "," as in:
var a = something,
b = somethingElse,
c = anything;
instead of using several "var" sentences. This is a good practice.
Hope this helps.

angular leaflet custom markers (using angular directives)

I'm trying to create a "leaflet marker" using an angular directive. For design purposes, we separate the presentation and the model so different persons can work on different parts of the application. My issue, more likely, is more a "scope" problem than a "leaflet" problem. I'm trying to pass an object to be used in the angular directive, while I'm adding the markers on "$scope", in the controller. That directive, "" in my app, is the only tag in my "message" property on each marker object to be presented in the map. It has an attribute "estacao" which in portuguese is the same as "station".
So, my code is here:
angular.forEach($scope.estacoes, function(estacao) {
$scope.markers.push({
lat: estacao.latitude,
lng: estacao.longitude,
message: "<popup estacao='estacoes[" + i + "]'></popup>"
});
i++;
});
http://plnkr.co/edit/evaQpqGZUz39Y7MNqbo7?p=preview
The problem seams to be that my "estacao" is null when the directive is processed.
Can anyone help me to figure out what is happening?
The 'auto' compile of the popup message (from the leaflet directive) uses the root scope.
So you need to assign your response estacoes to the root scope:
promiseEstacoes.then(function(estacoes) {
$rootScope.estacoes = estacoes.estacoes;
...
}
http://plnkr.co/edit/OkQcth2zNrEdO2rgwBv8?p=preview
With the latest versions of angular-leaflet-directive, you can specify a scope to use on message rendering:
$scope.markers.push({
lat: estacao.latitude,
lng: estacao.longitude,
getMessageScope: function() { return $scope; }
message: "<popup estacao='estacoes[" + i + "]'></popup>"
});

AngularJS Leaflet memory leak

There is a clear memory leak in my Angular app wherever I use the following leaflet directive: https://github.com/tombatossals/angular-leaflet-directive.
Note that the directive works fine, however the memory footprint continues growing as I leave and return to any view using the directive.
The directive builds off of the leaflet javascript library found here: https://github.com/Leaflet/Leaflet
I use the directive as follows:
<div ng-controller="Explore">
<div leaflet defaults="defaults" center="center" markers="markers" layers="layers"></div>
</div>
Inside my controller I extend the leaflet directive attributes to the scope:
angular.extend($scope, {
defaults: {
dragging: true,
doubleClickZoom: false,
scrollWheelZoom: false,
maxZoom: 12,
minZoom: 12
},
center: {
lat: $scope.cities[$scope.market.city][1],
lng: $scope.cities[$scope.market.city][0],
zoom: 12
},
markers: {},
layers: {
baselayers: {
google: {
name: 'Google Streets',
layerType: 'ROADMAP',
type: 'google'
}
}
}
});
I am not sure what is causing the memory leak, but I believe it may have to do with event listeners that are not removed when $destroy is called within the leaflet directive:
scope.$on('$destroy', function () {
leafletData.unresolveMap(attrs.id);
});
On destroy the function unresolveMap is called:
this.unresolveMap = function (scopeId) {
var id = leafletHelpers.obtainEffectiveMapId(maps, scopeId);
maps[id] = undefined;
};
This is as far as I got. If anyone has come across anything similar or has any ideas as to how to attack this issue further I would greatly appreciate it :)
You should try to remove completly the map by adding a map.remove() in the on $destroy handler (From leaflet API it should: "Destroys the map and clears all related event listeners").
scope.$on('$destroy', function () {
leafletData.unresolveMap(attrs.id);
map.remove();
});
Have you tried assigning an id attribute to your map? That's what the attrs.id refers to.
<leaflet id="myMap" defaults="defaults" center="center" markers="markers" layers="layers"></leaflet>

Resources