I am having one issue I was hoping someone would help me on. I am using Angular and the angular google maps directive. I have an event handler registered on idle so that I want to update what markers are shown but when the event is handled it returns the map and I've lost scope so I am unsure how to add new markers onto the map?
I setup a map like so:
<google-map center="map.center" zoom="map.zoom" events="map.events"> <markers> <marker ng-repeat="marker in map.markers" coords="marker"> </marker> </markers> </google-map>
That then uses the following to setup its initial values on events:
$scope.map = {
center: {
latitude: 45,
longitude: -73
},
zoom: 8,
events:{
idle:getJobs
},
markers:[]
};
When the event fires the getJobs function I have lost the scope so cannot push new markers onto the map with angular, any ideas??
function getJobs($scope) {
self = this;
JobService.getJobs(self.map).then(function(jobData){
for (var i = 0; i < jobData.length; i++) {
var job = jobData[i];
if (job.get('location') != null && job.get('location').longitude != null) {
$scope.map.markers.push(createJobMarker(job.get('role'),job.get('location').longitude,job.get('location').latitude),i);
}
}
});
}
Try
function getJobs($scope) {
self = this;
JobService.getJobs(self.map).then(function(jobData){
$scope.apply(function () {
for (var i = 0; i < jobData.length; i++) {
var job = jobData[i];
if (job.get('location') != null && job.get('location').longitude != null) {
$scope.map.markers.push(createJobMarker(job.get('role'),job.get('location').longitude,job.get('location').latitude),i);
}
}
});
});
}
Update:
I see, you are just losing reference to the scope variable. Try setting up your event like this:
$scope.map = {
center: {
latitude: 45,
longitude: -73
},
zoom: 8,
events:{
idle: function () {
getJobs($scope);
}
},
markers:[]
};
Related
I am using angular-google-maps v-2.3.3. I am loading markers using the "markers" directive and using map "idle" event for some manipulations. My problem is, Every time when the user zoom in or zoom out or pan the map, "idle" event is getting fired n number of times based on the number of markers with in the bounds. For eg: If there are 40 markers, The idle event is getting called 40 times instead of once. Below is my code where I am setting up the idle event.
angular.extend(vm, {
map: {
center: { latitude: 47, longitude: 2 },
markersControl: {},
mapControl: {},
events: {
tilesloaded: function(map) {
$scope.$apply(function() {
vm.mapInstance = map;
});
var map = vm.map.mapControl.getGMap();
$timeout(function() {
google.maps.event.trigger(map, 'resize');
}, 100);
},
dragend: dragend,
idle: function() {
try {
var markers = vm.map.markersControl.getGMarkers();
var map = vm.map.mapControl.getGMap();
for (var i = 0; i < markers.length; i++) {
if (map.getBounds().contains(markers[i].getPosition())) {
markers[i].setVisible(true);
} else {
markers[i].setVisible(false);
}
}
} catch (err) {
// Handle error(s) here
}
}
},
window: {
closeClick: function() {
var markers = vm.map.markersControl.getGMarkers();
markers.forEach(function(v, i) {
v.setAnimation(null);
});
}
}
}
});
I wanted to automatically center the map to the user's location once loaded so I used $scope.$apply() once geolocation is loaded as seen in my TestCtrl in controller.js here:
$scope.drawMap = function(position) {
$scope.$apply(function() {
$scope.myLocation.lng = position.coords.longitude;
$scope.myLocation.lat = position.coords.latitude;
$scope.map = {
center: {
latitude: $scope.myLocation.lat,
longitude: $scope.myLocation.lng
},
zoom: 14,
events: {
click: $scope.clickCallback
}
};
});
};
navigator.geolocation.getCurrentPosition($scope.drawMap);
$scope.test = function(){
alert("hola");
};
The $scope.clickCallback is used to push new markers to the map on click event.
// inside TestCtrl
var markers = [], counter = 1;
$scope.clickCallback = function(map, eventName, event){
var lat = event[0].latLng.lat();
var lng = event[0].latLng.lng();
markers.push(createNewMarker(counter, lat, lng));
$scope.$apply(function(){
$scope.newMarker = markers;
});
counter++;
};
As you can see, there's another $scope.$apply there to apply the new marker/s.
The createNewMarker() is where the markers (ui-gmap-markers) models is defined.
// still inside TestCtrl
var createNewMarker = function(i, lat, lng, idKey) {
if (idKey == null) {
idKey = "id";
}
var foo = "<h4>New Marker</h4><form><input type='text' placeholder='Event name' name='name'></input> <input type='button' value='submit'></input><input type='button' ng-click='test()' value='Delete marker'></input></form>";
var bar = $compile(foo)($scope);
var ret = {
latitude: lat,
longitude: lng,
show: true,
options: {
draggable: true,
animation: google.maps.Animation.DROP,
},
windows: {
title: "New Marker",
},
windowsOptions: {
content: foo,
}
};
ret[idKey] = i;
return ret;
};
Now the marker is showing fine when I click on the map including the window, but when I click on the Delete marker button, my $scope.test() function isn't firing up. I tried using $compile but it returns a bunch of error about $scope.
Here's my template:
<ion-content scroll="false">
<ui-gmap-google-map center='map.center' zoom='map.zoom' bounds="map.bounds" events="map.events">
<ui-gmap-markers models="newMarker" coords="'self'" icon="'icon'" options="'options'">
<ui-gmap-windows show="show" options="'windowsOptions'">
</ui-gmap-windows>
</ui-gmap-markers>
</ui-gmap-google-map>
</ion-content>
Anyone familiar with this scenario? I'm using Ionic Framework btw.
It does not have to be this complex.
As a creator of ngMap, I would recommend this,
http://ngmap.github.io/drawings.html#/marker-remove#marker-remove
To set the current location, just use current-location
<map center="current-location" zoom="12" on-click="addMarker()">
<marker ng-repeat="pos in positions" position="{{pos.lat}}, {{pos.lng}}"></marker>
</map>
http://plnkr.co/edit/e1SioHQ6NTSYCp0EbR0x?p=preview
I want to retrieve the longitude and latitude position of my click mouse event, but i can't, it gives me Undefined. Any one can help me please ?
I'm using AngularJS and I found that we can do
google.maps.event.addListener(map, 'click', function(event) {
console.log(event.latLng);
});
But I can't do so in my controller it gives me an error, or maybe i don't know how to use that!!
here is my code :
$scope.map = {
center: {
latitude: 36,
longitude: -80
},
events: {
"click": function (event) {
console.log(event.latLng);
}
}
}
and I tried that too but it gives me (Nan,Nan)
$scope.map = {
center: {
latitude: 36,
longitude: -80
},
events: {
"click": function (event) {
var pos = new google.maps.LatLng(event.latLng, event.latLng);
console.log("position: " + pos);
}
}
}
I could solve it like that
events: {
tilesloaded: function (map, eventName, originalEventArgs) {
//map is trueley ready then this callback is hit
},
click: function (mapModel, eventName, originalEventArgs) {
var e = originalEventArgs[0];
var lat = e.latLng.lat(),lon = e.latLng.lng();
console.log("lat long: "lat, lon);
$scope.$apply();
}
}
Hi I am using the angular-google-maps for my project. The html and js code is as follows
html:
<ui-gmap-markers models="apartments" coords="'loc'" icon="'assets/images/map_icon_normal.png'" idkey="'_id'"
fit="'false'" click="click">
<ui-gmap-windows show="'show'" >
<div ng-non-bindable>{{streetAddress}}</div>
</ui-gmap-windows>
</ui-gmap-markers>
</ui-gmap-google-map>
Script:
angular.module('myApp')
.controller('MapCtrl',
function ($scope, $routeParams, Map, uiGmapGoogleMapApi) {
$scope.apartments = [];
$scope.customIcon = "../../assets/images/map_icon_normal.png"
$scope.map = {
center: {
latitude: $routeParams.lat,
longitude: $routeParams.lon
},
zoom: 5,
bounds: {},
events: {
tilesloaded: function (map) {
//console.log('tiles loaded');
$scope.$apply(function () {
$scope.mapInstance = map;
//console.log(map.getBounds().getNorthEast());
$scope.searchbox.options.bounds = new google.maps.LatLngBounds($scope.mapInstance.getBounds().getNorthEast(),
$scope.mapInstance.getBounds().getSouthWest());
});
},
idle: function(map) {
$scope.map.refresh = false;
},
resize: function(map) {
console.log('resize');
},
dragend: function() {
}
},
markersEvents: {
click: function(marker, eventName, model, args) {
console.log('markerEvent click');
$scope.map.window.model = model;
$scope.map.window.show = true;
}
},
window : {
marker: {},
show: false,
closeClick: function() {
this.show = false;
},
options: {} // define when map is ready
},
control: {},
refresh: function () {
$scope.map.control.refresh();
}
}
uiGmapGoogleMapApi.then(function (map) {
$scope.getData(20, 0, map);
map.visualRefresh = true;
$scope.mapInstance = map;
})
$scope.getData = function(limit, offset, map) {
Map.getApartments($routeParams.lat, $routeParams.lon, limit, offset).success(function (data) {
///----- I get undefined error here---
$scope.map.control.refresh();
});
}})
}
I am not sure how to refresh the map with the new markers or even trigger an update to the map. I played around with 'control' and 'refresh' params of the ui-gmap-google-map but cannot get it to work.
You need to use uiGmapIsReady --- not uiGmapGoogleMapApi --- to wait for control objects to be augmented with their methods (such as refresh).
The uiGmapIsReady service provides a promise which resolves when all uiGmapGoogleMap directives have been fully initialized, while the uiGmapGoogleMapApi service resolves simply when the Google Maps JS API has loaded.
See this answer for an example of using uiGmapIsReady. And of course, don't forget the docs.
Regarding how to get updates to your models property on the scope to cause updates to your map, your code example needs to be fleshed out and cleaned up to help you there. (For example, what is the resolution of getApartments doing to update $scope.apartments? Or maybe asking that question is itself the answer?) Take a look at this fiddle, it might help you in the meantime.
Try dorebuildall attribute.
<ui-gmap-markers
models="apartments"
coords="'loc'"
icon="'assets/images/map_icon_normal.png'"
idkey="'_id'"
fit="'false'"
click="click"
dorebuildall="true">
<ui-gmap-windows></ui-gmap-windows>
</ui-gmap-markers>
More details at: http://angular-ui.github.io/angular-google-maps/
I'm using AngularJS for Google Maps and want to dynamically center and zoom a map based on multiple markers that are dynamically loaded. This is for a Cordova app using the Ionic Framework.
Here's my view:
<ion-view title="" ng-controller="MapCtrl as vm">
<ion-content class="padding">
<google-map id="mainMap" control="vm.googleMap" draggable="true" center="vm.map.center" zoom="vm.map.zoom" mark-click="false">
<markers idKey="mainMap" fit="vm.map.fit">
<marker idKey="marker.id" ng-repeat="marker in vm.map.markers" coords="marker.coords" options="marker.options">
<marker-label content="marker.name" anchor="2 0" class="marker-labels"/>
</marker>
</markers>
</google-map>
</ion-content>
</ion-view>
Here's my controller:
angular.module('myApp.controllers', [])
.controller('MapCtrl', function($scope, $ionicPlatform) {
var vm = this;
vm.googleMap = {}; // this is filled when google map is initialized, but it's too late
vm.mapMarkers = [];
vm.arrMarkers = [
{
id: "home",
name: "home",
coords: {
latitude:xxxxxxx, //valid coords
longitude:xxxxxxx //valid coords
},
options: {
animation: google.maps.Animation.BOUNCE
}
},
{
id: "placeAId",
name: "Place A",
coords: {
latitude:xxxxxxx, //valid coords
longitude:xxxxxxx //valid coords
}
},
{
id: "placeBId",
name: "Place B",
coords: {
latitude:xxxxxxx, //valid coords
longitude:xxxxxxx //valid coords
}
}
];
vm.map = {
center: { //how to determine where to center???
latitude: xxxxxxx, //valid coords
longitude: xxxxxxx //valid coords
},
zoom: 12, //how to determine zoom dynamically???
fit: true,
markers: vm.arrMarkers
};
var setMapBounds = function () {
var bounds = new google.maps.LatLngBounds();
createMarkers();
var markers = vm.mapMarkers;
for(var i=0; i<markers.length; i++) {
bounds.extend(markers[i].getPosition());
}
var map = vm.googleMap.control.getGMap();
map.setCenter(bounds.getCenter());
map.fitBounds(bounds);
//remove one zoom level to ensure no marker is on the edge.
map.setZoom(map.getZoom()-1);
// set a minimum zoom
// if you got only 1 marker or all markers are on the same address map will be zoomed too much.
if(map.getZoom()> 15){
map.setZoom(15);
}
};
var createMarkers = function() {
var map = vm.googleMap.control.getGMap(); //vm.googleMap.control is undefined because this fire before map is initialized
angular.forEach(vm.restaurants, function(restaurant, index) {
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(restaurant.coords.latitude, restaurant.coords.longitude),
title: restaurant.name
});
vm.mapMarkers.push(marker);
});
};
$ionicPlatform.ready(function() {
setMapBounds();
});
})
So, my question is how do I center and zoom the map using multiple dynamically loaded markers? Also, how do I get an instance of googleMap.control (vm.googleMap.control) before the map is loaded?
Here's my code just in case anyone was wondering how to do this locally. This is a simple solution for what I needed and my indeed go back to angualr-google maps, but as of now this works fine in my application.
angular.module('myApp.controllers', [])
.controller('MapCtrl', function($scope) {
var vm = this;
vm.googleMap = null;
vm.mapMarkers = [];
var onSuccess = function(position) {
vm.userLocation.coords.latitude = position.coords.latitude;
vm.userLocation.coords.longitude = position.coords.longitude;
initializeMap();
};
var onError = function(error) {
alert('code: ' + error.code + '\n' + 'message: ' + error.message);
};
vm.userLocation = {
id: "home",
title: "home",
coords: {
latitude: 33.636727,
longitude: -83.920702
},
options: {
animation: google.maps.Animation.BOUNCE
}
};
vm.places = [
{
id: "78869C43-C694-40A5-97A0-5E709AA6CE51",
title: "Place A",
coords: {
latitude: 33.625296,
longitude: -83.976206
}
},
{
id: "52319278-83AA-46D4-ABA6-307EAF820E77",
title: "Place B",
coords: {
latitude: 33.576522,
longitude: -83.964981
}
}
];
var addMarkers = function() {
var userLocation = new google.maps.Marker({
map: vm.googleMap,
position: new google.maps.LatLng(vm.userLocation.coords.latitude, vm.userLocation.coords.longitude),
//animation: vm.userLocation.options.animation,
title: vm.userLocation.title
});
vm.mapMarkers.push(userLocation);
angular.forEach(vm.places, function(location, index) {
var marker = new google.maps.Marker({
map: vm.googleMap,
position: new google.maps.LatLng(location.coords.latitude, location.coords.longitude),
title: location.title
});
vm.mapMarkers.push(marker);
});
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < vm.mapMarkers.length; i++) {
bounds.extend(vm.mapMarkers[i].getPosition());
}
vm.googleMap.setCenter(bounds.getCenter());
vm.googleMap.fitBounds(bounds);
//remove one zoom level to ensure no marker is on the edge.
vm.googleMap.setZoom(vm.googleMap.getZoom() - 1);
// set a minimum zoom
// if you got only 1 marker or all markers are on the same address map will be zoomed too much.
if (vm.googleMap.getZoom() > 15) {
vm.googleMap.setZoom(15);
}
};
var initializeMap = function() {
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoom: 12,
center: new google.maps.LatLng(vm.userLocation.coords.latitude, vm.userLocation.coords.longitude)
};
var div = document.getElementById("map_canvas");
//var map = plugin.google.maps.Map.getMap(div, mapOptions);
vm.googleMap = new google.maps.Map(div, mapOptions);
addMarkers();
var width = screen.width;
var height = screen.height;
};
navigator.geolocation.getCurrentPosition(onSuccess, onError);
})
Your previous answer is good but doesn't include usage of the google maps directives you mentioned in the begining of the post. There is a way to do it using those directives, here is how:
Assuming we are in the directive's scope
Define scope.mapControl = {}; - this will have new access methods for map and markers
When defining your markup for the directives - for map and marker - include this control attribute to be added:
<ui-gmap-google-map center='map.center' zoom='map.zoom' control="mapControl">
<ui-gmap-marker ng-repeat="location in locations" coords="location.coordinates" options="location.markerOptions" idkey="location.id" control="mapControl">
<ui-gmap-window options="location.markerWindowOptions" closeclick="closeMarkerWindow(location.id)" show="true">
<div>{{location.description}}</div>
</ui-gmap-window>
</ui-gmap-marker>
</ui-gmap-google-map>
In your directive's event or some method:
var map = scope.mapControl.getGMap();
var markers = scope.mapControl.getGMarkers();
var bounds = map.getBounds();
for (var i = 0; i < markers.length; i++) {
bounds.extend(markers[i].getPosition());
}
map.setCenter(bounds.getCenter());
map.fitBounds(bounds);
map.setZoom(map.getZoom() - 1);