Creating Google Maps Sample App with AngularJS and Onsen UI

This sample application has the purpose of demonstrating how to combine elements of Onsen UI, a framework for creating hybrid HTML5 apps, AngularJS, a JavaScript framework developed by Google, and Google Maps JavaScript API v3.

****Please note that this article was written in 2015. Onsen UI released its version 2 in October 2016 and many things have changed since then. If you are interested in map integration to your cordova app, also check out more recent article by Andi.****

This application has been developed using Monaca, a cloud based mobile app development environment that supports iOS/Android/Windows 8 hybrid apps in one source. The benefit of using Monaca to develop this sample application is dictated by the fact that this product provides a native support for Onsen UI, default templates and user-friendly development environment that allows developers to skip the installation and configuration of the frameworks used in this project.

The features implemented in this application are quite simple: the purpose is not to create a large application with complicated features, but to create a template which can be extended in the future. That’s why some elements, like the search bar and the settings page, have only been implemented without offering any real functionality, but, at the same time, are ready to be associated with any behaviour the programmer wishes to implement.

https://andipavllo.github.io/Google-Maps-Onsen-UI-Sample/www/index.html

The implemented features are:

  • Add Marker, via screen long press
  • Delete single Marker, via screen press (on the Marker)
  • Delete all Markers, via <ons-button>
  • Calculate the distance (partial and total) between the Markers, via <ons-button>
  • Menu, via <ons-sliding-menu>

The main interface consists of an <ons-sliding-menu> associated with two pages: map.html and settings.html. The first one will contain the map element and Onsen UI elements like <ons-button>. The user is free to navigate between these two pages using the sliding menu element.

You can try the app using the sample above, or directly from the browser by clicking here. The code is also available on GitHub at this link.

Except the HTML content illustrated above, the application contains two other key elements: controller.js and style.css.

Controllers

The controllers contain the logic of the application. To build this app we need two controllers, one for the management of the ons-sliding-menu and one for the map interaction. Both controllers can be found in the file controller.js.

SlidingMenuController

One of the biggest trouble of having a ons-sliding-menu element and a Google Map element is that both have an event associated with the scroll action, in this case the horizontal one. That’s why is it is mandatory for creation of a controller to adapt the behaviour of the sliding menu swipe functionality to the current situation. Adding a listener on the element that controls every time a 'postopen' or 'postclose' event is triggered is the way to fix this issue. The sliding menu swipe functionality is disabled by default, it will be enabled only after the menu is opened from a ons-toolbar-button click and will be available only until the menu is closed, via swipe or again via ons-toolbar-button. The listener is created after the first time the sliding menu has been opened.

MapController

This controller contains all the logic related to the map object and the interactions with the Onsen UI elements. The first step is the declaration of the Markers array, which will be used later, and of the map element. To initialize the map we had to use AngularJS’s timer service $timeout and put a delay of 100ms before the map’s initialization. This step is necessary because AngularJS’s controller initialization occur before the DOM is loaded.

After the map is loaded, it is necessary to add a listener related to the hard press event, which is associated with adding a new Marker. To implement this feature we have used the library Hammer.JS, which is natively included in Onsen UI.

After the map’s initialization occurred, the user is free to perform the basic implemented features that were listed before. Each one of these features is associated with a method, more precisely $scope.addOnClick(), $scope.deleteAllMarkers() and $scope.calculateDistance().

The first method, $scope.addOnClick(), is associated with the listener that was introduced above. First of all it takes the X and Y value of the hardclicked/hardpressed point on the screen and try to convert it in latitude and longitude coordinates. This step is necessary because the points displayed on Google Maps are encoded with this format. To perform this action, we use the function:

$scope.overlay.getProjection().fromContainerPixelToLatLng(point);

It is important to consider that the coordinates origin will start from the top-left point of the div when the map is contained, and not from the top-left of the device’s screen. That’s why, when we take the Y coordinate, we have to decrease is by (-) 44px, since 44px is the height of the <ons-toolbar> element which is situated on the top of the screen. After the coordinates conversion, our marker is ready to be added in the markers array and to be displayed on the map.

At this point it is necessary to create a listener associated with the click/press event on one of the markers. If a marker will be pressed, a ons.notification.confirm element will appear, asking the user if he wants to delete the marker. Based on the user’s choice, the relative action will be executed and an ons.notification.alert element will be displayed.

The method $scope.deleteAllMarkers() is very simple: it just scans the marker’s array and deletes any marker from the map. At the end, it deletes all the elements from the array and initialize the index variable to its initial value.

The last method is $scope.calculateDistance(), which calculates the distance from two or more markers on the map, using a formula that can easily be found on the web. To perform this operation, we don’t need to perform any conversion, as we did before, because the coordinates are expressed with the same encoding elaborated by the formula. After the elaboration is over, a ons.notification.confirm element will ask the user if he also wants to see the partial distances between the markers. The results of this choice will be again displayed with a ons.notification.alert element.

CSS

Beyond the default CSS sheet provided by Onsen UI, it’s necessary to define new style properties of the DOM elements. The content of the CSS can be found in style.css. The main purpose of this sheet is to dispose in a proper way the elements of the Google Maps JavaScript API v3 and of Onsen UI. A full fusion is not possible because of the differences between the two products, that’s why it is necessary to define two layers in which the different elements to display.

The lower layer will contain the Google Maps elements, like the map and the markers, meanwhile the upper layer will contain Onsen UI elements. This action has been performed mainly thanks to the z-indexproperty: assigning a lower z-index value to the maps elements will push them in a lower level than the Onsen UI elements, which have a higher value.

It is very important to specify the position of Onsen UI’s elements correctly, as to not overlap them on Google Maps’s ones. It’s also very important to consider the resolution of the screen to position the elements correctly. Also the element’s size is very important, for example a div that is too big will overlay the map, making impossible any interaction with it.

HTML

The application is organized into four pages: index.html, menu.html, map.html and settings.html (which will not be described). Each one of these pages is a combination of HTML, Onsen UI and AngularJS elements. The structure of the application is based on Onsen’s Sliding Menu template that can be found as a pre-made template in Monaca. I chose this template because it seemed to me the most appropriate one, but nothing prohibits you from using another one that adapts better to your idea of the organization of the DOM.

index.html

This is, of course, the main page of the application, the one loaded by default. Just after the HTML opening tag, we can find ng-app="myApp", the directive used to auto-bootstrap an AngularJS application. This directive designates the root element of the application and is typically placed near the root element of the page - e.g. on the <body> or <html> tags.

After the scripts and css sheets inclusion, we need to include a Google Map Key Script in our application, in order to be able to display the map content. To be honest, from the last version of Google Maps JavaScript API, a key is no more mandatory, but is highly recommended in order to monitor your data usage and purchase additional data quota. You can find additional information about how to obtain a free Google Maps API Key at this link.

The tag to include, in order to display the map, is:

<script type="text/javascript"     
src="https://maps.googleapis.com/maps/api/js">
</script>

At this point we can analyze the body content. As you can see, inside the body there is only an <ons-sliding-menu> element. It is the root of all the Onsen UI’s elements in the application and is characterized by some attributes as var="slidingMenu", which is used for the two way data binding inside AngularJS, menu-page="menu.html" which is the page that contains the HTML of the sliding menu, and main-page="map.html", which is the main page displayed by default. Furthermore, the menu, as explained before, is set by default as unswipeable by the attribute swipeable="false".

menu.html

This page contains the auto generated code for the <ons-sliding-menu> element. Inside we can find a <ons-list> with two <ons-list-item> which contain the redirect at map.html and settings.html. In case you want to add more pages inside the application, it’s necessary to create new items to permit an easy navigation of the app content.

map.html

This is probably the most important page of the application, the one that contains the map and most of the Onsen UI’s elements. At the top of it, we can find the declaration of the controller ng-controller="MapController". Considering that the controller is declared on the root element, its visibility will be extended to each element of the page.

Immediately above it, we can find a <ons-toolbar> element, which contains the title of the page and an <ons-toolbar-button> which is designed to open and close the sliding menu. For this reason, inside the <ons-toolbar> is placed another controller declaration, precisely ng-controller="SlidingMenuController".

The rest of the code is the one that displays the map, the search bar and the two <ons-button>.

Conclusion

In this tutorial, you have learned how to create an application using Onsen UI, Google Maps JavaScript API v3 and AngularJS. You now have a basic layout to customize as you wish. Just remember that a lot of features are already provided by Google Maps API, so check them out before trying to implement all by yourself.


Originally published at onsen.io on February 19, 2015.