AngularJS From Beginning: Google Map API With AngularJS - Part 17

I am here to continue the discussion around AngularJS. Today, we will discuss how to utilize google map api with angular js. Also in case you have not had a look at our previous articles of this series, go through the following links:

In this article, we will discuss how use AngularJS with google map API.

On today’s Web, mapping solutions are a natural ingredient. We use them to see the location of things, to search for the position of an address, to get driving directions, and to do numerous other things. Most information has a location, and if something has a location, it can be displayed on a map. There are several mapping solutions including Yahoo! Maps and Bing Maps, but the most popular one is Google Maps. In fact, according to Programmableweb.com, it’s the most popular API on the Internet. According to the site’s May 2010 statistics, 43 percent of all mashups use the Google Maps API (www.programmableweb.com/apis). In comparison, the second most popular API was Flickr with 11 percent, and the second most popular mapping API was VirtualEarth (Bing Maps) with 3 percent. Applications and web sites that are combining data or functionality from two or more sources are commonly referred to as mashups. Mashups are becoming increasingly popular and have revolutionized the way information is being used and visualized. Mapping solutions are one important ingredient in a lot of these mashups. The Google Maps API lets you harness the power of Google Maps to use in your own applications to display your own (or others’) data in an efficient and usable manner.

A Brief History

Google Maps was introduced in a blog post on Google in February 2005. It revolutionized the way maps on web pages work by letting the user drag the map to navigate it. This was new at the time. The map solutions used then were expensive and required special map servers, yet they didn’t deliver the same level of interactivity. Google Maps was originally developed by two Danish brothers, Lars and Jens Rasmussen. They cofounded Where 2 Technologies, a company dedicated to creating mapping solutions. The company was acquired by Google in October 2004, and the two brothers then created Google Maps. (They are also the men behind Google Wave.) Before there was a public API, some developers figured out how to hack Google Maps to incorporate maps on their own web sites. This led Google to the conclusion that there was a need for a public API, and in June 2005 it was publically released. The first mashup on the Internet is often considered to be Housingmaps.com, a combination of Google Maps with realty listings from Craiglist.org plotted on it. It was in fact created before the public API was released and was hacked together by developer Paul Rademacher. At the time, this was pretty revolutionary and started a new era of mashing information from different sources. During the Google I/O conference in May 2009, version 3 of the API, which this book is about, was announced. And in May 2010 (incidentally also during the Google I/O conference and during the making of this book), it was announced as graduated from beta. It’s now the recommended choice for new Google Maps applications and the next step in the history of Google Maps.

How It Works

When seeing the dynamic nature of Google Maps, you might think there is something magical going on under the hood. But there’s really nothing magical about it. It’s just HTML, CSS, and JavaScript working together. The map tiles are images that are loaded in the background with Ajax calls and then inserted into a <div> in the HTML age. As you navigate the map, the API sends information about the new coordinates and zoom levels of the map in Ajax calls that return new images. And that’s it! No magic involved whatsoever. The API itself basically consists of JavaScript files that contain classes with methods and properties that you can use to tell the map how to behave.

A New API

The new API is a complete remake. It not only features a brand new is also completely rewritten under the hood. Why did the Google Maps team take such a drastic measure?

Slimmed-Down Feature Set

Back when the Google Maps API was first API but built, other JavaScript libraries such as Prototype, MooTools, and jQuery weren’t available. That’s the reason the Maps API contains methods for making Ajax calls and other things that we now rely on other third-party libraries to do for us. Nowadays, we also rely on debugging tools such as the Firefox extension Firebug and the built-in tools in IE8 and Chrome/Safari for debugging our code. These haven’t been available that long either, so the old Maps API contains classes for writing debugging information in a console window. Apart from that, the old API was originally created for serving Google’s own mapping solution found at www.google.com/maps. This service contains a lot of features that most mappers don’t need, making the API even more bloated. Since 2005, an explosion in mobile use of web content has occurred. The old API wasn’t intended to be used on these devices and is therefore slower than necessary. Attempts to make the old API faster on these devices have been made, but because of its architecture, developers have been limited in what they’ve been able to accomplish. For this reason, Google decided to build the new API from scratch.

For demonstrating google map api, I created an angular js custom directive for google map and then used that directly in a page.
 
App.js
  1. var testApp = angular.module('TestApp', []);  
GoogleMap directive
  1. testApp.directive('googleMap', function (googleMapApi) {  
  2.     return {  
  3.         restrict: 'EA',  
  4.         scope: {  
  5.             param: '='  
  6.         },  
  7.         template: '<div id="googlemaps" data-ng-style={"border":"solid","border-color":"red","width":param.width,"height":param.height}>' +  
  8.                   '</div>',  
  9.         replace: true,  
  10.         controller: function ($scope, $element, $attrs, googleMapApi) {  
  11.   
  12.             var method = function () {  
  13.                 var initAttribute = function () {  
  14.                     if (!angular.isDefined($scope.param)) {  
  15.                         $scope.param = {};  
  16.                     }  
  17.   
  18.                     if (!angular.isDefined($scope.param.height)) {  
  19.                         $scope.param.height = '100%';  
  20.                     }  
  21.   
  22.                     if (!angular.isDefined($scope.param.width)) {  
  23.                         $scope.param.width = '100%';  
  24.                     }  
  25.                     if (!angular.isDefined($scope.param.autoZoom)) {  
  26.                         $scope.param.autoZoom = true;  
  27.                     }  
  28.                     if (!angular.isDefined($scope.param.allowMultipleMark)) {  
  29.                         $scope.param.allowMultipleMark = true;  
  30.                     }  
  31.                     googleMapApi.then(mapConfig);  
  32.                 }  
  33.   
  34.                 var assignMethod = function () {  
  35.                     $scope.param.method = {  
  36.                         setMark: function (latitude, longitude, title, desc) {  
  37.                             setMapMarker($scope.map, new google.maps.LatLng(latitude, longitude), title, desc)  
  38.                         }  
  39.                     }  
  40.                 }  
  41.   
  42.                 var mapConfig = function () {  
  43.                     $scope.infoWindow = '';  
  44.                     $scope.markers = [];  
  45.   
  46.                     $scope.mapOptions = {  
  47.                         center: new google.maps.LatLng(50, 2),  
  48.                         zoom: 4,  
  49.                         mapTypeId: google.maps.MapTypeId.ROADMAP,  
  50.                         scrollwheel: $scope.param.autoZoom  
  51.                     };  
  52.                     method.initMap();  
  53.   
  54.                 }  
  55.   
  56.                 var initMap = function () {  
  57.                     if ($scope.map === void 0) {  
  58.                         $scope.map = new google.maps.Map($element[0], $scope.mapOptions);  
  59.                     }  
  60.                 }  
  61.   
  62.                 var setMapMarker = function (map, position, title, content) {  
  63.                     var marker;  
  64.                     var markerOptions = {  
  65.                         position: position,  
  66.                         map: map,  
  67.                         title: title,  
  68.                         icon: 'https://maps.google.com/mapfiles/ms/icons/green-dot.png'  
  69.                     };  
  70.   
  71.                     marker = new google.maps.Marker(markerOptions);  
  72.                     if ($scope.param.allowMultipleMark)  
  73.                         $scope.markers.push(marker);  
  74.                     else  
  75.                         $scope.markers = marker;  
  76.   
  77.                     google.maps.event.addListener(marker, 'click', function () {  
  78.                         // close window if not undefined  
  79.                         if (infoWindow !== void 0) {  
  80.                             infoWindow.close();  
  81.                         }  
  82.                         // create new window  
  83.                         var infoWindowOptions = {  
  84.                             content: content  
  85.                         };  
  86.                         infoWindow = new google.maps.InfoWindow(infoWindowOptions);  
  87.                         infoWindow.open($scope.map, marker);  
  88.                     });  
  89.                 }  
  90.   
  91.                 return {  
  92.                     initAttribute: initAttribute,  
  93.                     mapConfig: mapConfig,  
  94.                     initMap: initMap,  
  95.                     assignMethod: assignMethod  
  96.                 }  
  97.             }();  
  98.   
  99.             var init = function () {  
  100.                 method.initAttribute();  
  101.                 method.assignMethod();  
  102.             }();  
  103.         }  
  104.     };  
  105. });  
Google map api service
  1. testApp.service('googleMapApi', function googleMapApi($window, $q) {  
  2.   
  3.     function loadScript() {  
  4.         console.log('loadScript')  
  5.         // use global document since Angular's $document is weak  
  6.         var s = document.createElement('script')  
  7.         s.src = '//maps.googleapis.com/maps/api/js?sensor=false&language=en&callback=initMap'  
  8.         document.body.appendChild(s);  
  9.     }  
  10.   
  11.     var deferred = $q.defer()  
  12.   
  13.     $window.initMap = function () {  
  14.         deferred.resolve()  
  15.     }  
  16.   
  17.     if ($window.attachEvent) {  
  18.         $window.attachEvent('onload', loadScript)  
  19.     } else {  
  20.         $window.addEventListener('load', loadScript, false)  
  21.     }  
  22.   
  23.     return deferred.promise  
  24. });  
index.html
  1. <!DOCTYPE html>  
  2. <html xmlns="http://www.w3.org/1999/xhtml" data-ng-app="TestApp">  
  3. <head>  
  4.     <title>Google Map</title>  
  5.     <link href="map.css" rel="stylesheet" />  
  6.     <script src="../../RefScript/jquery-2.1.1.js"></script>  
  7.     <script src="angular.min.js"></script>  
  8.     <script src="app.js"></script>  
  9.     <script src="mapController.js"></script>  
  10. </head>  
  11. <body data-ng-controller="mapController">  
  12.     <h2>Google Map</h2>  
  13.     <google-map param="googleMapArgs"></google-map>  
  14.     <input type="button" value="Mark in Map" data-ng-click="fnClick();" />  
  15.     <br />  
  16.     Search Address : <input type="text" data-ng-model="address" data-ng-style="{'width':googleMapArgs.width}" ng-model-options="{debounce:1000}" ng-change="fnSearchAddress();" />  
  17.     <br />  
  18.     <div class="tt-suggestion" style="white-space: nowrap; cursor: pointer;"  
  19.          data-ng-repeat="item in mapData | limitTo :10" data-ng-click="selectItem($index,item)">  
  20.         <p style="white-space: normal;">{{item.formatted_address}}</p>  
  21.     </div>  
  22.   
  23. </body>  
  24. </html>  
MapController.js
  1. testApp.controller('mapController', function ($scope, $http) {  
  2.     $scope.googleMapArgs = {  
  3.         width: '50%',  
  4.         height: '50%',  
  5.         allowMultipleMark:false  
  6.     }  
  7.   
  8.     $scope.fnClick = function () {  
  9.         $scope.googleMapArgs.method.setMark(51.508515, -0.125487, 'London', 'Just some content');  
  10.     }  
  11.   
  12.     $scope.fnSearchAddress = function () {  
  13.         $http.get('http://maps.google.com/maps/api/geocode/json?address=' + $scope.address + '&sensor=false')  
  14.             .success(function (mapData) {  
  15.                 $scope.mapData = mapData.results;  
  16.             });  
  17.     }  
  18.   
  19.     $scope.selectItem = function (index, item) {  
  20.         $scope.googleMapArgs.method.setMark(item.geometry.location.lat, item.geometry.location.lng, item.formatted_address, item.formatted_address);  
  21.     }  
  22. });  
The output of the above code is as below,