I am trying to have an input field that when submitted adds a marker to my Google Map. Right now when I submit the field it is creating the object but the marker is not being displayed. Right now I am able to get a location to show up if it is hard coded in but not when I add a new one. (I know that the view right now is only for the hard coded one, I have that so the current code is working)
Here is my code:
My View:
<form>
<input type="number" class="" ng-model="marker.markerLat" required="">
<input type="number" class="" ng-model="marker.markerLng" required="">
<button class="button" ng-click="addMarker(marker)">Add</button>
</form>
<google-map center="map.center" zoom="map.zoom">
<marker coords="marker.coords" options="marker.options" idkey="marker.id" >
</marker>
</google-map>
My Controller:
//Default location
$scope.map = {
center: {
latitude: 32.7833,
longitude: -79.9333
},
zoom: 11
}
$scope.options = {scrollwheel: true};
$scope.markers = [];
$scope.addMarker = function (marker) {
$scope.markers.push({
latitude: parseFloat($scope.markerLat),
longitude: parseFloat($scope.markerLng)
});
console.log('Maker add: ' + $scope.markers);
$scope.markerLat ="";
$scope.markerLng ="";
};
$scope.marker = {
id:0,
coords: {
latitude: 32.7833,
longitude: -79.9333
}
}
I would advice you to create a custom angular directive for your map.
But anyway, angular is not enough to get what you want working. You have to create google.maps objects. And set the map property of your marker to the map you have created.
Here is a little example :
.directive('map', function () {
return {
template: '<div></div>',
restrict: 'EA',
replace: true,
link: function (scope, element) {
scope.markers = [];
scope.map = new google.maps.Map(element[0], {
center: new google.maps.LatLng(32.7833, -79.9333),
zoom: 11
});
scope.addMarker = function (lat, lnt) {
var marker = new google.maps.Marker({
map: scope.map,
position: new google.maps.LatLng(lat, lng)
});
scope.markers.push(marker);
};
}
});
So you simply have to call the addMarker function with a lat and lng parameter. Use angular events to communicate between your controller and directive. More info about the methods here
Related
Can someone please guide me through the process of including and integrating javascript google maps api in angularjs project on webstorm. Generally I have done this by using simple html file, but when I try to include the same google maps api and code in an angularjs project, the view of maps is not rendered. Thanks, I'll be really greatefull for the help.
this is an example how to integrate google maps in your angularjs project
javascript:
angular.module('myApp', []).
directive('myMap', function() {
// directive link function
var link = function(scope, element, attrs) {
var map, infoWindow;
var markers = [];
// map config
var mapOptions = {
center: new google.maps.LatLng(50, 2),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
};
// init the map
function initMap() {
if (map === void 0) {
map = new google.maps.Map(element[0], mapOptions);
}
}
// place a marker
function setMarker(map, position, title, content) {
var marker;
var markerOptions = {
position: position,
map: map,
title: title,
icon: 'https://maps.google.com/mapfiles/ms/icons/green-dot.png'
};
marker = new google.maps.Marker(markerOptions);
markers.push(marker); // add marker to array
google.maps.event.addListener(marker, 'click', function () {
// close window if not undefined
if (infoWindow !== void 0) {
infoWindow.close();
}
// create new window
var infoWindowOptions = {
content: content
};
infoWindow = new google.maps.InfoWindow(infoWindowOptions);
infoWindow.open(map, marker);
});
}
// show the map and place some markers
initMap();
setMarker(map, new google.maps.LatLng(51.508515, -0.125487), 'London', 'Just some content');
setMarker(map, new google.maps.LatLng(52.370216, 4.895168), 'Amsterdam', 'More content');
setMarker(map, new google.maps.LatLng(48.856614, 2.352222), 'Paris', 'Text here');
};
return {
restrict: 'A',
template: '<div id="gmaps"></div>',
replace: true,
link: link
};
});
html:
<div my-map=""></div>
css:
#gmaps {
width: 450px;
height: 450px;
}
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 am using AngularJS google maps to display map with markers.
The scenario is :
Initially Contact Details like Door no, Street, Area etc fields page will be displayed along with a static map. Once an edit button is clicked a pop-up with all the fields and map is displayed.
ex:
CODE:
html
<div class="row" ng-controller="userProfileController">
<ui-gmap-google-map center="center1" zoom="zoom1" pan="true" events="events">
<ui-gmap-markers models="models1" coords="'self'" options="'options'"></ui-gmap-markers>
</ui-gmap-google-map>
</div>
controller
$scope.center1 = {
latitude: lat,
longitude: lng
};
$scope.zoom1 = 8;
$scope.models1 = [{
id: 11445522,
latitude: lat,
longitude: lng,
options: {
title: "Current Location"
}
}];
Well everything works fine so far.
When edit is clicked i am trying to load another html in the modal that contains fields and a map. This time the map isn't loading. if I press 'F12' then map can be seen.
Code for popup:
html
<div class="col-sm-12">
<ui-gmap-google-map center="center3" zoom="zoom3" pan="true" events="events3" refresh="true">
<ui-gmap-markers doRebuildAll="true" doCluster="true" models="models3" coords="'self'" options="'options'"></ui-gmap-markers>
</ui-gmap-google-map>
controller
$scope.center3 = {latitude: 19.20742852680121,
longitude: 73.553466796875
};
$scope.zoom3 = 7;
$scope.models3 = [{
id: 5421222,
latitude: 19.20742852680121,
longitude: 73.553466796875,
options: {
title: "User Location"
}
}];
What might be the issue.? Can someone help me?
It displays like this:
I had a similar problem, but in my case, the user input an address and return the location. I found on the Internet the solution, and with some adjustments, I decided this way...
First, I create myController in app.js
app.controller('myController'), function ($scope) {
// my variable that's control my modal
$scope.showModal = false;
// my click event, like your 'Edit' button
$scope.createModal = function () {
$scope.showModal = true;
};
}
HTML index.html
<my-modal visible="showModal"></my-modal>
HTML modal.html
<div class="form-group">
<input type="text" class="form-control" ng-model="chosenPlace" details="chosenPlaceDetails" googleplace placeholder="Address"/>
<div class="map_container">
<div id="map_canvas" class="map_canvas"></div>
</div>
</div>
Then, in my modal.js, I created two Directive's
// Directive of Google Maps
angular.module('modal', [])
.directive('googleplace', function () {
return {
require: 'ngModel',
scope: {
ngModel: '=',
details: '=?'
},
controller: function ($scope) {
$scope.gPlace;
$scope.map;
$scope.marker;
$scope.initMap = function () {
// Set the initial lat and lng
var latlng = new google.maps.LatLng(-20.00, -47.00);
var options = {
zoom: 5,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
$scope.map = new google.maps.Map($("#map_canvas")[0], options);
$scope.marker = new google.maps.Marker({
map: $scope.map,
draggable: true,
});
$scope.marker.setPosition(latlng);
};
$scope.initMap();
},
link: function(scope, element, attrs, model) {
var options = {
types: ['geocode'],
componentRestrictions: { country: 'us' }
};
scope.gPlace = new google.maps.places.Autocomplete(element[0], options);
google.maps.event.addListener(scope.gPlace, 'place_changed', function() {
scope.$apply(function() {
google.maps.event.trigger(scope.map, 'resize');
var location = new google.maps.LatLng(scope.gPlace.getPlace().geometry.location.A, scope.gPlace.getPlace().geometry.location.F);
scope.marker.setPosition(location);
scope.map.setCenter(location);
scope.map.setZoom(16);
});
});
}
};
});
.directive('myModal', function () {
return {
templateUrl: 'modal.html',
restrict: 'E',
replace: true,
scope: true,
controller: function ($scope) {
},
link: function postLink(scope, element, attrs) {
scope.$watch(attrs.visible, function(value) {
if(value == true) {
$(element).modal('show');
}
else {
$(element).modal('hide');
}
});
$(element).on('shown.bs.modal', function(){
scope.$apply(function(){
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function(event){
scope.$apply(function(){
scope.$parent[attrs.visible] = false;
});
});
}
};
});
When the user write his address, and hit Enter, the listener on the map, find the address and marker on the map.
I did like that because it was the best solution I found for my project.
I hope that helps.
PS: Sorry my english :/
my html page renders the map by this:
<ui-gmap-google-map center='map.center' zoom='map.zoom'>
<ui-gmap-markers models="markers" coords="'coords'" icon="'icon'" ></ui-gmap-markers>
</ui-gmap-google-map>
And this is the controller:
angular.module('controllers.mapscontroller', [])
.controller("MapCtrl", function($scope, uiGmapGoogleMapApi, dataFactory) {
$scope.POIs=[];
$scope.markers = [];
uiGmapGoogleMapApi.then(function(maps) {
$scope.map = { center: { latitude: 40.3555013, longitude: 18.1573811 }, zoom: 8 };
navigator.geolocation.getCurrentPosition(function (position) {
$scope.map = { center: { latitude: position.coords.latitude, longitude: position.coords.longitude }, zoom: 8 };
});
dataFactory.getPOIs("it-IT")
.success(function (data) {
$scope.POIs=data.data.contents;
$scope.initializePOIsOnMap();
})
.error(function (error) {
console.log(error);
});
});
$scope.removePOIs = function() {
$scope.markers=[]; //<-- does nothing !!!
};
$scope.initializePOIsOnMap = function() {
for(var POI in $scope.POIs) {
var marker = {
id: $scope.POIs[POI].id,
coords: {
latitude: $scope.POIs[POI].latitude,
longitude: $scope.POIs[POI].longitude
},
options: { draggable: false , visible:true},
icon: "img/catIcons/"+$scope.POIs[POI].catid+".png"
};
$scope.markers.push(marker);
}
}
});
Maps gets displayed correctly, and markers as well.
But unfortunately, as you can read in $scope.removePOIs function, I can't remove the markers from the map. I've tried different solutions found over stackoverflow and the Web ($scope.markers.length=0, marker.setMap(null), ...) but no luck.
Any hint??
Thanks
Roberto
Solved!!
The problem was that I specified the controller twice: in the app.js and in the HTML page. The reason for specifying it in the HTML page is that I use the switchery plugin, which requires the ng-controller attribute to be set in the tag.
I removed the controller property from the app.js, putted all the HTML (the maps tags) within the tag and now it works.
Thanks!
Roberto
Here's an example of deleting markers using angularjs:
Example
Look at the script for remove markers example.
I have just switched from KnockoutJS to AngularJS and I am not able to find the KnockoutJS's "with" data-bind in AngularJS.
Here is the piece of code in KnockoutJS. The "with" binding creates a new binding context, so that descendant elements are bound in the context of a specified object.
<h1 data-bind="text: city"> </h1>
<p data-bind="with: coords">
Latitude: <span data-bind="text: latitude"> </span>,
Longitude: <span data-bind="text: longitude"> </span>
</p>
<script type="text/javascript">
ko.applyBindings({
city: "London",
coords: {
latitude: 51.5001524,
longitude: -0.1262362
}
});
</script>
Does AngularJS have anything like context?
Nothing like with that I know of.. this is the best I could do:
<h1>{{city}}</h1>
<p ng-repeat="c in [coords.or.possibly.deeper.in.tree]">
Latitude: {{c.latitude}},
Longitude: {{c.longitude}}
</p>
Create a custom directive that loops through the source object and creates corresponding properties on the directive's scope that are getter/setter references to the source object.
Check out this plunker.
directive module:
angular.module('koWith', [])
.directive('koWith', function () {
return {
controller: function ($scope, $attrs) {
var withObj = $scope.$parent[$attrs.ngWith];
function getter(prop) {
return this[prop];
}
function setter(val, prop) {
this[prop] = val;
}
for (var prop in withObj) {
if (withObj.hasOwnProperty(prop)) {
Object.defineProperty($scope, prop, {
enumerable: true,
configurable: true,
get: getter.bind(withObj, prop),
set: setter.bind(withObj, prop)
});
}
}
},
restrict: 'A',
scope: true
};
});
app module:
angular.module('myApp', [])
.controller('myController', function ($scope) {
$scope.customer = {
name: "Timmeh",
address: {
address1: "12 S Street",
address2: "",
city: "South Park",
state: "CO",
zipCode: "80440"
}
};
});
html:
<div ko-with="customer">
<h2>{{name}}</h2>
<div ko-with="address">
{{address1}}<br>
{{address2}}<br>
{{city}}, {{state}} {{zipCode}}
</div>
</div>
Explanation
In KnockoutJS, bindings keep the bindingContext and data separated so creating the with binding is trivial since it only needs to create a new child bindingContext from the current one and use the with object as its data value.
In AngularJS, a directive's scope is basically the bindingContext and data object rolled into one. When a new scope is created, in order to get the with-like behavior, the properties of the with object have to be referenced onto the newly created scope object.
Here is solution based on #nwayve, but it supports expressions in koWith and also it watches for updating property/expression specified in koWith:
.directive('koWith', function () {
return {
restrict: 'A',
scope: true,
controller: function ($scope, $attrs, $parse) {
var ScopePropertyDesc = function (prop) {
var self = this;
self.propName = prop;
self.parsed = $parse(prop);
self.enumerable = true;
self.configurable = true;
//self.writable = true;
self.get = function () {
var withObj = $scope.$parent[$attrs.koWith];
var res = self.parsed($scope.$parent, withObj);
return res;
};
self.set = function (newValue) {
var withObj = $scope.$parent[$attrs.koWith];
self.parsed.assign(withObj, newValue);
};
};
$scope.$parent.$watch($attrs.koWith, function (oldVal, newVal) {
var withObj = $scope.$parent[$attrs.koWith];
(function copyPropertiesToScope(withObj) {
for (var prop in withObj) {
if (withObj.hasOwnProperty(prop)) {
Object.defineProperty($scope, prop, new ScopePropertyDesc(prop));
}
};
})(withObj);
});
}
};
});