Let's add location to our parties.
The most popular maps widget is Google Maps so let's use that.
First, let's add the angular-google-maps Meteor package:
meteor npm install --save angular-google-maps
We also have to install another package:
meteor npm install --save angular-simple-logger
Then let's create a PartyMap
component:
1
2
3
4
5
<div class="angular-google-map-container">
<ui-gmap-google-map center="partyMap.location || partyMap.map.center" events="partyMap.map.events" zoom="partyMap.map.zoom">
<ui-gmap-marker coords="partyMap.location" options="partyMap.marker.options" events="partyMapmarker.events" idKey="party-location"></ui-gmap-marker>
</ui-gmap-google-map>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import angular from 'angular';
import angularMeteor from 'angular-meteor';
import 'angular-simple-logger';
import 'angular-google-maps';
import template from './partyMap.html';
class PartyMap {
constructor($scope) {
'ngInject';
this.map = {
center: {
latitude: 45,
longitude: -73
},
zoom: 8,
events: {}
};
this.marker = {
options: {
draggable: true
},
events: {}
};
}
}
const name = 'partyMap';
// create a module
export default angular.module(name, [
angularMeteor,
'nemLogging', // https://github.com/angular-ui/angular-google-maps/issues/1633
'uiGmapgoogle-maps'
]).component(name, {
template,
controllerAs: name,
bindings: {
location: '='
},
controller: PartyMap
});
Here we created the google-map directive with attributes for binding the center, handling events and zoom of the map.
We created the this.map
variable to hold the properties on the map.
To display a Google Map widget we have to define it's height and width. Let's do that now.
Create a new file named partyMap.css
inside a the same folder as the component.
1
2
3
4
.angular-google-map-container {
height: 400px;
width: 400px;
}
We still have to import this file:
3
4
5
6
7
8
9
import 'angular-simple-logger';
import 'angular-google-maps';
import './partyMap.css';
import template from './partyMap.html';
class PartyMap {
Now we have to add it to the PartyDetails:
7
8
9
10
11
12
13
75
76
77
78
79
80
81
82
import template from './partyDetails.html';
import { Parties } from '../../../api/parties';
import { name as PartyUninvited } from '../partyUninvited/partyUninvited';
import { name as PartyMap } from '../partyMap/partyMap';
class PartyDetails {
constructor($stateParams, $scope, $reactive) {
...some lines skipped...
export default angular.module(name, [
angularMeteor,
uiRouter,
PartyUninvited,
PartyMap
]).component(name, {
template,
controllerAs: name,
9
10
11
12
13
<button ui-sref="parties">Back</button>
<party-uninvited party="partyDetails.party" ng-show="partyDetails.canInvite()"></party-uninvited>
<party-map location="partyDetails.party.location"></party-map>
Now run the app and go to the party details page. You should see a new Google Map widget, but it doesn't do anything yet.
Let's add a marker that will be bound to the party's location.
Inside PartyMap
template:
1
2
3
4
5
<div class="angular-google-map-container">
<ui-gmap-google-map center="partyMap.location || partyMap.map.center" events="partyMap.map.events" zoom="partyMap.map.zoom">
<ui-gmap-marker coords="partyMap.location" options="partyMap.marker.options" events="partyMapmarker.events" idKey="party-location"></ui-gmap-marker>
</ui-gmap-google-map>
</div>
The ui-gmap-marker
directive represents a marker inside the map. We use the following attributes:
We already extended this.map
variable to include handling those options.
Inside PartyMap
component:
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
longitude: -73
},
zoom: 8,
events: {
click: (mapModel, eventName, originalEventArgs) => {
this.setLocation(originalEventArgs[0].latLng.lat(), originalEventArgs[0].latLng.lng());
$scope.$apply();
}
}
};
this.marker = {
options: {
draggable: true
},
events: {
dragend: (marker, eventName, args) => {
this.setLocation(marker.getPosition().lat(), marker.getPosition().lng());
$scope.$apply();
}
}
};
}
setLocation(latitude, longitude) {
this.location = {
latitude,
longitude
};
}
}
What happened here:
Now is the time to use it in the PartyDetails.
Insert location
value:
57
58
59
60
61
62
63
64
$set: {
name: this.party.name,
description: this.party.description,
public: this.party.public,
location: this.party.location
}
}, (error) => {
if (error) {
Again, with the great Meteor platform there is no need for sync or save function. We just set it and it syncs in all other clients.
Test it to see clicking and dragging works.
Now let's add a map to the parties list to show all the parties on the map.
So let's create the PartiesMap
component:
1
2
3
4
5
<div class="angular-google-map-container">
<ui-gmap-google-map center="partiesMap.map.center" zoom="partiesMap.map.zoom">
<ui-gmap-markers models="partiesMap.parties" coords="'location'" fit="true" idkey="'_id'" doRebuildAll="true"></ui-gmap-markers>
</ui-gmap-google-map>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import angular from 'angular';
import angularMeteor from 'angular-meteor';
import 'angular-simple-logger';
import 'angular-google-maps';
import template from './partiesMap.html';
/**
* PartiesMap component
*/
class PartiesMap {
constructor() {
this.map = {
center: {
latitude: 45,
longitude: -73
},
zoom: 8
};
}
}
const name = 'partiesMap';
// create a module
export default angular.module(name, [
angularMeteor,
'nemLogging', // https://github.com/angular-ui/angular-google-maps/issues/1633
'uiGmapgoogle-maps'
]).component(name, {
template,
controllerAs: name,
bindings: {
parties: '='
},
controller: PartiesMap
});
You can see that the difference between the directive we used in PartyMap
is that ui-gmap-markers
is plural.
The attributes we use:
And use it in the PartiesList
:
8
9
10
11
12
13
14
77
78
79
80
81
82
83
import template from './partiesList.html';
import { Parties } from '../../../api/parties';
import { name as PartiesSort } from '../partiesSort/partiesSort';
import { name as PartiesMap } from '../partiesMap/partiesMap';
import { name as PartyAdd } from '../partyAdd/partyAdd';
import { name as PartyRemove } from '../partyRemove/partyRemove';
import { name as PartyCreator } from '../partyCreator/partyCreator';
...some lines skipped...
uiRouter,
utilsPagination,
PartiesSort,
PartiesMap,
PartyAdd,
PartyRemove,
PartyCreator,
31
32
33
34
35
36
</ul>
<dir-pagination-controls on-page-change="partiesList.pageChanged(newPageNumber)"></dir-pagination-controls>
<parties-map parties="partiesList.parties"></parties-map>
Depends on which version of google-maps you use, by now you might have encountered the following error message when trying to load the map component:
Oops! Something went wrong. This page didn't load Google Maps correctly. See the JavaScript console for technical details.
The map fails to load because in the newer versions of google-maps an API key is mandatory. An API key is a code passed in by computer programs calling an API to identify the calling program, its developer, or its user to the Web site. To generate an API key go to Google Maps API documentation page and follow the instructions. Each app should have it's own API key, as for now we can just use an API key we generated for the sake of this tutorial, but once you go production mode, replace the API key in the script below:
1
2
3
4
5
6
<head>
<base href="/">
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDbphq9crcdpecbseKX3Yx2LPxMRqWK-rc"></script>
</head>
<body>
<socially></socially>
Run the app. Look at how little code we needed to add maps support to our app.
Angular 1 has a huge eco system full of great directives like the angular-google-maps one.