Creating Google Maps Sample App with AngularJS and Onsen UI
****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.
The implemented features are:
- Add Marker, via screen long press
- Delete single Marker, via screen press (on the Marker)
- Delete all Markers, via
- Calculate the distance (partial and total) between the Markers, via
- Menu, via
The main interface consists of an
<ons-sliding-menu> associated with two pages:
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.
Except the HTML content illustrated above, the application contains two other key elements:
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
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
'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.
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
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:
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.
$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
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
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.
The application is organized into four pages:
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.
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
The tag to include, in order to display the map, is:
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
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
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.
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
The rest of the code is the one that displays the map, the search bar and the two
Originally published at onsen.io on February 19, 2015.