Working example of angular-google-maps search function - angularjs

Does anyone have an example of a working search box like the one the angular-google-maps-team is showing under 'search-box' on this site: https://angular-ui.github.io/angular-google-maps/#!/api
If you write something it sure does find it in a dropdown, but when you press enter, the map doesn't respond. - How can you make the map move to the correct location when you hit enter?

html:
<ui-gmap-google-map center="map.center" zoom="map.zoom" draggable="true">
<ui-gmap-search-box template="searchbox.template" events="searchbox.events" position="BOTTOM_RIGHT"></ui-gmap-search-box>
<ui-gmap-marker coords="marker.coords" options="marker.options" events="marker.events" idkey="marker.id">
</ui-gmap-google-map>
js controller:
$scope.map = {
"center": {
"latitude": 52.47491894326404,
"longitude": -1.8684210293371217
},
"zoom": 15
}; //TODO: set location based on users current gps location
$scope.marker = {
id: 0,
coords: {
latitude: 52.47491894326404,
longitude: -1.8684210293371217
},
options: { draggable: true },
events: {
dragend: function (marker, eventName, args) {
$scope.marker.options = {
draggable: true,
labelContent: "lat: " + $scope.marker.coords.latitude + ' ' + 'lon: ' + $scope.marker.coords.longitude,
labelAnchor: "100 0",
labelClass: "marker-labels"
};
}
}
};
var events = {
places_changed: function (searchBox) {
var place = searchBox.getPlaces();
if (!place || place == 'undefined' || place.length == 0) {
console.log('no place data :(');
return;
}
$scope.map = {
"center": {
"latitude": place[0].geometry.location.lat(),
"longitude": place[0].geometry.location.lng()
},
"zoom": 18
};
$scope.marker = {
id: 0,
coords: {
latitude: place[0].geometry.location.lat(),
longitude: place[0].geometry.location.lng()
}
};
}
};
$scope.searchbox = { template: 'searchbox.tpl.html', events: events };

I suggest you look at examples sent to angular-google-maps github.
There's a piece of JavaScript lacking in 123Tax response which is found at https://github.com/angular-ui/angular-google-maps/blob/master/example/assets/scripts/controllers/search-box.js
And this snippet is loaded in https://github.com/angular-ui/angular-google-maps/blob/master/example/search-box.html

// the following controls the map in your Controller
$scope.map = { control: {}, center: { latitude: 37.70, longitude: -122.344 }, zoom: 9, refresh: {}};
function placeToMarker(searchBox, id) {
var place = searchBox.getPlaces();
if (!place || place == 'undefined' || place.length == 0) {
return;
}
var marker = {
id: id,
place_id: place[0].place_id,
name: place[0].name,
address: place[0].formatted_address,
latitude: place[0].geometry.location.lat(),
longitude: place[0].geometry.location.lng(),
latlng: place[0].geometry.location.lat() + ',' + place[0].geometry.location.lng()
};
// push your markers into the $scope.map.markers array
if (!$scope.map.markers) {
$scope.map.markers = [];
}
// THIS IS THE KEY TO RECENTER/REFRESH THE MAP, to your question
$scope.map.control.refresh({latitude: marker.latitude, longitude: marker.longitude});
// the following defines the SearchBox on your Controller; events call placeToMarker function above
var searchBoxEvents = {
places_changed: function (searchBox) {
placeToMarker(searchBox, id);
}
};
// this is defined on the Controller, as well. This specifies which template searchBoxEvents should match to; note the parentdiv
$scope.searchBox = { template:'searchBox.template.html', events:searchBoxEvents, parentdiv: 'searchBoxParent'};
// in your HTML, declare where you want the searchBox. parentdiv: 'searchBoxParent' above looks for the id="searchBoxParent" in HTML
<div class="col-xs-12 col-md-12" id="searchBoxParent">
<script type="text/ng-template" id="searchBox.template.html">
<input type="text" ng-model="address" placeholder="Search Address" required />
</script>
</div>
//Lastly, in HTML, make sure you wrap ui-gmap-search-box & ui-gmap-markers in ui-gmap-google-map
<ui-gmap-google-map id="map-canvas" center="map.center" zoom="map.zoom" draggable="true" options="options" control="map.control">
<ui-gmap-search-box template="searchBox.template" events="searchBox.events" parentdiv="searchBox.parentdiv"></ui-gmap-search-box>
<ui-gmap-markers idkey="map.idkey" models="map.markers" coords="'self'" icon="'icon'" click="'onClicked'" fit="true"></ui-gmap-markers>
</ui-gmap-google-map>

Gavin's answer is correct,just some more details about the 'searchbox.tpl.html of his example.
It has to be placed outside of the directive like this:
<body>
<div id="searchBoxParent"></div>
<div id="map_canvas" ng-controller="mainCtrl">
<script type="text/ng-template" id="searchbox.tpl.html">
<input type="text" placeholder="Search Box">
</script>
<ui-gmap-google-map center="map.center" zoom="map.zoom" draggable="true" options="options">
<ui-gmap-search-box template="searchbox.template" events="searchbox.events" parentdiv="searchbox.parentdiv"></ui-gmap-search-box>
</ui-gmap-google-map>
</div>
<!--example-->
</body>
Working plunkr: http://embed.plnkr.co/1rpXQhcZqwJ7rv0tyK9P/ (for some reason the plunkr only worked in chrome for me but not in firefox)
I could not comment on Gavin's answer because of lack of repution, this is why I add the info as additional answer.

Related

angular-google-maps update model

How to update the model to load a new dataset of markers?
<ui-gmap-google-map center="map.center" zoom="map.zoom" bounds="map.bounds" refresh="map.refresh">
<ui-gmap-markers
models="dataset"
coords="'self'"
icon="'icon'"
doCluster='10'
click="onClick"
>
<ui-gmap-windows show="show">
<div ng-non-bindable>
<h3 class="gray3-text fz13 mbottom0">{{title}}</h3>
</div>
</ui-gmap-windows>
</ui-gmap-markers>
I am changing the dataset from outside the ui-gmap-google-map directive, like so
<p ng-click="changeDataset('allUsers')" class="cursor-pointer">
<p ng-click="changeDataset('allQuotations')" class="cursor-pointer">
the function is this:
scope.changeDataset = function(){
switch (dataset) {
case 'allResellers':
scope.dataset = scope.allResellers;
break;
case 'allQuotations':
scope.dataset = scope.allQuotations;
break;
case 'allUsers':
scope.dataset = scope.allUsers;
break;
case 'allMarkers':
scope.dataset = scope.allMarkers;
break;
}
};
my scope.dataset changes but it doesn't update the markers in the map.
PS: modelsbyref="false" doesn't work.
Adding control="markerControl" to ui-gmap-google-map worked, but had to use this workaround:
angular.element(document.getElementsByClassName('angular-google-map')).scope().markerControl.updateModels(newDataset);
<ui-gmap-google-map center="map.center" zoom="map.zoom" bounds="map.bounds">
<ui-gmap-markers
models="dataset"
coords="'self'"
icon="'icon'"
doCluster='10'
click="onClick"
control="markerControl"
>
<ui-gmap-windows show="show">
<div ng-non-bindable>
<h3 class="gray3-text fz13 mbottom0">{{title}}</h3>
</div>
</ui-gmap-windows>
</ui-gmap-markers>
Since the changeDataset function expects dataset name, after the following changes:
$scope.changeDataset = function(dataset) {
switch (dataset) {
case 'allResellers':
$scope.dataset = $scope.allResellers;
break;
case 'allQuotations':
$scope.dataset = $scope.allQuotations;
break;
case 'allUsers':
$scope.dataset = $scope.allUsers;
break;
case 'allMarkers':
$scope.dataset = $scope.allMarkers;
break;
}
};
the map model is getting updated properly.
Working example
angular.module('appMaps', ['uiGmapgoogle-maps'])
.controller('mapCtrl', function($scope, uiGmapGoogleMapApi) {
$scope.dataset = [
{ id: 1, title: "Brisbane", latitude: -33.867396, longitude: 151.206854 },
{ id: 2, title: "Sydney", latitude: -27.46758, longitude: 153.027892 },
{ id: 3, title: "Perth", latitude: -31.953159, longitude: 115.849915 }
];
$scope.allResellers = [];
$scope.allQuotations = [
{ id: 1, title: "Q1", latitude: -31.867396, longitude: 144.206854 },
{ id: 2, title: "Q2", latitude: -28.46758, longitude: 152.027892 }
];
$scope.allUsers = [
{ id: 1, title: "User1", latitude: -36.867396, longitude: 145.206854 },
{ id: 2, title: "User2", latitude: -33.46758, longitude: 142.027892 },
];
$scope.allMarkers = [];
uiGmapGoogleMapApi.then(function(maps) {
$scope.map = {
center: { latitude: -30, longitude: 135.0 },
zoom: 4,
control: {},
markerEvents: {
click: function(marker) {
}
},
options: $scope.mapOptions
};
});
$scope.mapOptions = {};
$scope.changeDataset = function(dataset) {
switch (dataset) {
case 'allResellers':
$scope.dataset = $scope.allResellers;
break;
case 'allQuotations':
$scope.dataset = $scope.allQuotations;
break;
case 'allUsers':
$scope.dataset = $scope.allUsers;
break;
case 'allMarkers':
$scope.dataset = $scope.allMarkers;
break;
}
};
});
.angular-google-map-container { height: 480px; }
<script src="https://code.angularjs.org/1.3.14/angular.js"></script>
<script src="http://rawgit.com/nmccready/angular-simple-logger/master/dist/angular-simple-logger.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-google-maps/2.2.1/angular-google-maps.min.js"></script>
<div ng-app="appMaps" ng-controller="mapCtrl">
<p ng-click="changeDataset('allUsers')" class="cursor-pointer" >Display users</p>
<p ng-click="changeDataset('allQuotations')" class="cursor-pointer" >Display quotations</p><br/>
<ui-gmap-google-map center="map.center" zoom="map.zoom" bounds="map.bounds" refresh="map.refresh">
<ui-gmap-markers models="dataset" coords="'self'" icon="'icon'" doCluster='10' click="onClick">
<ui-gmap-windows show="show">
<div ng-non-bindable>
<h3 class="gray3-text fz13 mbottom0">{{title}}</h3>
</div>
</ui-gmap-windows>
</ui-gmap-markers>
</div>
Same problem as in this question angular-google-maps updating marker model
It seems like whenever we update markers angularjs doesn't update it immediately. just call $scope.$digest() after pushing new marker to the array.
Also check $scope.$apply() function, it calls $scope.$digest() automatically.
Please refer to this tutorial which explain in detail:
tutorial showing $scope.$digest(), $scope.$apply, $scope.watch
Its written in above tutorial:
You may encounter some corner cases where AngularJS does not call the $digest() function for you. You will usually detect that by noticing that the data bindings do not upate the displayed values. In that case, call $scope.$digest() and it should work. Or, you can perhaps use $scope.$apply()

Angular Google Maps, Directive inside Info Window isn't binding data

I'm using Angular google Maps trying to get an info window working. When a marker is selected, the window is placed there and shown. Its content is some text and also some directives. The directives inside even work, except for when I try to bind some data its attributes.
In this case I'm having a rating directive (shows a bunch of stars) that takes a number attribute, as so:
<div stars number="person.rating"></div>
Note that this directives works just fine in a couple of other places in my app. Also, when I replace person.rating' for3, the directive renders perfectly. when I useperson.rating` outside of this div, it returns a number as expected.
Only when I combine the person.rating inside the number attribute, inside the window directive, do things go awry:
<ui-gmap-google-map center='map.center' class="big-maps" options='map.options' events="map.events" zoom='map.zoom'>
<ui-gmap-window coords="selectedCoords" show="windowOptions.visible" closeClick="closeWindow">
<div>
Name: {{person.firstName}}, Rating: {{person.rating}} <!-- these work just fine. -->
<div> So here we are. {{person.rating}}</div> <!-- this also works just fine. -->
<div stars number="3"></div> <!-- Even this works fine. -->
<div stars number="person.rating"></div> <!-- But this doesn't... -->
</div>
</ui-gmap-window>
<ui-gmap-markers
models='markers'
idKey='id'
coords="'coords'"
icon="'icon'"
options="'options'"
doCluster="false"
click="showWindow"
>
</ui-gmap-markers>
</ui-gmap-google-map>
The directive:
ndtApp.directive('stars', stars);
function stars() {
return {
restrict: "AE",
replace: 'true',
scope: {
number: "=",
size: "#"
},
templateUrl: "shared/stars/stars.html",
controller: controller
};
}
function controller($scope){
$scope.getEmptyStarsArray = getEmptyStarsArray;
$scope.getStarsArray = getStarsArray;
$scope.ratingSize = "";
activate();
function activate(){
if ($scope.size == 'sm'){
$scope.ratingSize = 'rating-sm';
} else if ($scope.size == 'lg'){
$scope.ratingSize = 'rating-lg';
}
console.log($scope.number);
}
function getEmptyStarsArray(){
if ($scope.number === undefined) return 0;
var rating = Math.round($scope.number);
if (rating > 4) return null;
return new Array(5 - rating);
}
function getStarsArray(){
if ($scope.number === undefined) return 0;
var rating = Math.round($scope.number);
if (rating === 0) return null;
if (rating > 5) return new Array(5);
return new Array(rating);
}
}
stars.html:
<div class="stars">
<span ng-repeat="i in getStarsArray() track by $index" class="{{ratingSize}} rating glyphicon glyphicon-star"></span><span ng-repeat="i in getEmptyStarsArray() track by $index" class="{{ratingSize}} rating glyphicon glyphicon-star-empty"></span>
</div>
Any help is highly appreciated!
It seems directive scope property is not getting bound, try to change scope for number property from number: "=" to number: "#" and directive initialization from <div stars number="person.rating"></div> to <div stars number="{{person.rating}}"></div>
Below is provided a working similar example:
var appMaps = angular.module('appMaps', ['uiGmapgoogle-maps']);
appMaps.controller('mainCtrl', function($scope,uiGmapIsReady) {
$scope.map = {
center: { latitude: 40.1451, longitude: -99.6680 },
zoom: 4,
options: { scrollwheel: false }
};
$scope.windowOptions = { visible: false };
var getRandomLat = function() {
return Math.random() * (90.0 + 90.0) - 90.0;
};
var getRandomLng = function () {
return Math.random() * (180.0 + 180.0) - 180.0;
};
var getRandomRating = function() {
return Math.floor(Math.random() * 11);
};
var createRandomMarker = function(i) {
var ret = {
latitude: getRandomLat(),
longitude: getRandomLng(),
title: 'Hotel #' + i,
show: false,
id: i
};
return ret;
};
$scope.onClick = function(marker, eventName, model) {
$scope.windowOptions.visible = true;
$scope.selectedHotel = model;
$scope.rating = { number: getRandomRating()};
};
$scope.closeWindow = function () {
$scope.windowOptions.visible = false;
};
$scope.hotels = [];
for (var i = 0; i < 256; i++) {
$scope.hotels.push(createRandomMarker(i));
}
});
appMaps.directive('rating',
function() {
return {
restrict: "AE",
replace: true,
scope: {
//number: "=",
number: "#"
},
controller: ratingController,
//template: '<div >Rating: {{ ::number }}</div>',
template: function(tElem, tAttrs){
return '<div class="rating"> Rating:' + tAttrs.number + '</div>';
}
};
});
function ratingController($scope){
console.log($scope.number);
}
html, body, #map_canvas {
height: 100%;
width: 100%;
margin: 0px;
}
#map_canvas {
position: relative;
}
.angular-google-map-container {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
<script src="https://code.angularjs.org/1.3.14/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
<script src="http://rawgit.com/angular-ui/angular-google-maps/2.0.X/dist/angular-google-maps.js"></script>
<div id="map_canvas" ng-app="appMaps" ng-controller="mainCtrl">
<ui-gmap-google-map center="map.center" zoom="map.zoom" draggable="true" options="options" events="map.events">
<ui-gmap-window coords="selectedHotel" show="windowOptions.visible" closeclick="closeWindow">
<div>
<div>{{selectedHotel.title}}</div>
<div rating number="{{rating.number}}"></div>
</div>
</ui-gmap-window>
<ui-gmap-markers models="hotels" coords="'self'" icon="'icon'" click="onClick">
</ui-gmap-markers>
</ui-gmap-google-map>
</div>

AngularJS ng-click not firing using angular-google-maps' windows

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

angular google map searchbox - places_changed is not called from the $route.current controller

I'm having an issue with angular google maps and the search box.
Even if the ng-view onLoad works as expected, after typing in the search box, the places_changed callbacks are not called from the correct controller but only from the first one (and the default) defined in $routeProvider.
You can find more details below:
Part of the template:
<div ng-controller="map">
<div>
<script type="text/ng-template" id="searchbox.tpl.html">
<input type="text" placeholder="Search Place..." class="google-maps-search">
</script>
<ui-gmap-google-map center='map.center' events="map.events" options="map.options" zoom='map.zoom'>
<ui-gmap-search-box template="map.searchbox.template" events="map.searchbox.events" position="BOTTOM_RIGHT"></ui-gmap-search-box>
<ui-gmap-marker coords="map.marker.coords" options="map.marker.options" events="map.marker.events" idkey="map.marker.id"></ui-gmap-marker>
<ui-gmap-markers models="mapMarkers" coords="'self'" icon="'icon'">
<ui-gmap-windows show="show">
<div ng-non-bindable>{{title}}</div>
</ui-gmap-windows>
</ui-gmap-markers>
</ui-gmap-google-map>
</div>
<div><div ng-view="" onload="renderView()"></div></div>
Part of the parent controller:
app.controller('map', function ($scope, $log, $location) {
$scope.map = {
events: {
click: function(map, eventName, args) {}
},
marker: {
id: 0,
coords: {
latitude: $scope.lat,
longitude: $scope.lng
},
options: { draggable: true }
},
searchbox: {
template: 'searchbox.tpl.html',
events: {
places_changed: function (searchBox) {}
}
}
};
});
And the following in each of the children controllers (defined in $routeProvider):
$scope.map.searchbox.events.places_changed = function (searchBox) {
var place = searchBox.getPlaces();
if (!place || place == 'undefined' || place.length == 0) {
console.log('no place data :(');
return;
}
$scope.lat = place[0].geometry.location.lat();
$scope.lng = place[0].geometry.location.lng();
$scope.map.center = {
"latitude": $scope.lat,
"longitude": $scope.lng
};
$scope.renderView();
};
Do you have any ideas?

Set Google Maps bounds with angular-google-maps

I'm trying to set bounds into Google Maps instance but with no success. I'm using AngularJS and angular-google-maps module. My last try was:
<div id="map_canvas">
<ui-gmap-google-map
center="map.center"
zoom="map.zoom"
bounds="map.bounds"
options="options">
<div ng-repeat="d in devicesMarkers track by d.id">
<ui-gmap-marker
idkey="d.id"
coords="d.center"
options="d.options">
</ui-gmap-marker>
<ui-gmap-circle
center="d.center"
stroke="d.circle.stroke"
fill="d.circle.fill"
radius="d.circle.radius"
visible="d.options.visible">
</ui-gmap-circle>
</div>
</ui-gmap-google-map>
</div>
In my app.js I wrote:
(...)
.controller('TaihMapController', ['$scope', '$log', 'uiGmapGoogleMapApi', function($scope, $log, GoogleMapApi) {
$scope.devicesMarkers = devices;
$scope.map = {
center: { latitude: devices[0].center.latitude, longitude: devices[0].center.longitude },
zoom: 12,
bounds: {}
// fit: true,
};
GoogleMapApi.then(function(maps) {
$log.debug(maps);
var myBounds = new maps.LatLngBounds();
for (var k = 0; k < devices.length; k++) {
var _tmp_position = new maps.LatLng(
devices[k].center.latitude,
devices[k].center.longitude);
myBounds.extend(_tmp_position);
}
$scope.map.bounds = myBounds;
$scope.googleVersion = maps.version;
// $scope.bounds = myBounds;
// $scope.zoom = maps.getZoom();
// maps.fitBounds(myBounds);
// $scope.bounds = maps.getBounds();
});
The function maps.fitBounds() doesn't exist. I try the $scope.map.bounds approach, but didn't respond the way I think.
If you're using angular-google-map's "markers" directive, just add the fit="true" attribute (ui-gmap-markers).
Example :
<ui-gmap-google-map center="map.center" zoom="map.zoom" options="map.options">
<ui-gmap-markers fit="true" models="markers" coords="'self'"></ui-gmap-markers>
</ui-gmap-google-map>
Source:
https://stackoverflow.com/a/29707965
According to docs, directives bounds is slightly different with google maps bounds. You should explicitly set northeast and southwest attributes with their own latitude and longitude.
Below should work:
$scope.map.bounds = {
northeast: {
latitude: myBounds.getNorthEast().lat(),
longitude: myBounds.getNorthEast().lng()
},
southwest: {
latitude: myBounds.getSouthWest().lat(),
longitude: myBounds.getSouthWest().lng()
}
};

Resources