Impelemting a Google Map API

I have started an ionic app for work, and one of the features of the cross platform arm is integrating a a Google map api. Currently I am focusing on mostly android side.

So far I had no issues with ionic framework and generally really enjoying. But right now I face a brick wall with trying to get google map working.
To give some details I am currently trying to get a JavaScript API v3 working with the app, and it works fine when I test it in the browser, no issues. But when I run on android device, and crashes and gives me a “Black Screen Of Death”. I cant do anything about. I tried googling the issues, and there is little to find about the solution, what I noticed though is that the issues is common. But the solution is not precise, no concrete work around.

I have tried looking into integrating cordova for this, and it’s still giving me issues. Since I am new and a noob at this, I got little knowledge on how to go about this.

Please help me out!!!

This are some code that is giving me errors

        angular.module('myDrive', ['ionic', "angular-data.DSCacheFactory", "google-maps".ns()]) // 'starter.services', 'starter.controllers'
    
    .run(function($ionicPlatform, DSCacheFactory) {
      $ionicPlatform.ready(function() {
        // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
        // for form inputs)
        if(window.cordova && window.cordova.plugins.Keyboard) {
          cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
        }
        if(window.StatusBar) {
          // org.apache.cordova.statusbar required
          StatusBar.styleDefault();
        }
        //var div = document.getElementById("map_canvas");
        //var map = plugin.google.maps.Map.getMap(div);
    
        DSCacheFactory("leagueDataCache", { storageMode: "localStorage", maxAge: 5000, deleteOnExpire: "aggressive"});
        DSCacheFactory("leaguesCache", { storageMode: "localStorage", maxAge: 5000, deleteOnExpire: "aggressive"});
        DSCacheFactory("myTeamsCache", { storageMode: "localStorage"});
        DSCacheFactory("staticCache", { storageMode: "localStorage"});
      });
    })


View for the map

    <ion-view title="Location Map" ng-controller="LocationMapCtrl as vm">
            <ion-content class="has-header">
    
    
            <ui-gmap-google-map draggable="true" center="vm.map.center" zoom="vm.map.zoom">
    
            </ui-gmap-google-map>
            </ion-content>
    </ion-view>


Controller for the map

(function() {
    'use strict';

    // Aim of the conntroller is to screate $scope. $scope is used to communicate with the view
    angular.module('myDrive').controller('LocationMapCtrl', ['$stateParams', LocationMapCtrl]);

    function LocationMapCtrl($stateParams) {
        var vm = this;

        vm.locationId = Number($stateParams.id);

        vm.map = {
            center: {
                latitude: 55.418192,
                longitude: 10.382617,
            },
            zoom : 16
        };
        vm.marker = { }
    };
})();  

And this is the error that log cat is giving me

 Error: [$injector:modulerr] Failed to instantiate module uiGmapgoogle-maps due to:
11-22 14:51:12.833 I/chromium(24024): Error: [$injector:nomod] Module 'uiGmapgoogle-maps' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure t
hat you specify the dependencies as the second argument.


     Error: [$injector:modulerr] Failed to instantiate module uiGmapgoogle-maps due to:
    11-22 14:51:12.833 I/chromium(24024): Error: [$injector:nomod] Module 'uiGmapgoogle-maps' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure t
    hat you specify the dependencies as the second argument.


 http://errors.angularjs.org/1.2.25/$injector/modulerr?p0=uiGmapgoogle-maps&p1=Error%3A%20%5B%24injector%3Anomod%5D%20Module%20'uiGmapgoogle-maps'%20is%20not%20a
vailable!%20You%20either%20misspelled%20the%20module%20name%20or%20forgot%20to%20load%20it.%20If%20registering%20a%20module%20ensure%20that%20you%20specify%20the%20dependencies%20as%20the%20second%20a
rgument.%0Ahttp%3A%2F%2Ferrors.angularjs.org%2F1.2.25%2F%24injector%2Fnomod%3Fp0%3DuiGmapgoogle-maps%0A%20%20%20%20at%20file%3A%2F%2F%2Fandroid_asset%2Fwww%2Flib%2Fionic%2Fjs%2Fionic.bundle.js%3A7703%
3A12%0A%20%20%20%20at%20file%3A%2F%2F%2Fandroid_asset%2Fwww%2Flib%2Fionic%2Fjs%2Fionic.bundle.js%3A9302%3A17%0A%20%20%20%20at%20ensure%20(file%3A%2F%2F%2Fandroid_asset%2Fwww%2Flib%2Fionic%2Fjs%2Fionic
.bundle.js%3A9226%3A38)%0A%20%20%20%20at%20module%20(file%3A%2F%2F%2Fandroid_asset%2Fwww%2Flib%2Fionic%2Fjs%2Fionic.bundle.js%3A9300%3A14)%0A%20%20%20%20at%20file%3A%2F%2F%2Fandroid_asset%2Fwww%2Flib%
2Fionic%2Fjs%2Fionic.bundle.js%3A11503%3A22%0A%20%20%20%20at%20forEach%20(file%3A%2F%2F%2Fandroid_asset%2Fwww%2Flib%2Fionic%2Fjs%2Fionic.bundle.js%3A7950%3A18)%0A%20%20%20%20at%20loadModules%20(file%3
A%2F%2F%2Fandroid_asset%2Fwww%2Flib%2Fionic%2Fjs%2Fionic.bundle.js%3A11497%3A5)%0A%20%20%20%20at%20file%3A%2F%2F%2Fandroid_asset%2Fwww%2Flib%2Fionic%2Fjs%2Fionic.bundle.js%3A11504%3A40%0A%20%20%20%20a
t%20forEach%20(file%3A%2F%2F%2Fandroid_asset%2Fwww%2Flib%2Fionic%2Fjs%2Fionic.bundle.js%3A7950%3A18)%0A%20%20%20%20at%20loadModules%20(file%3A%2F%2F%2Fandroid_asset%2Fwww%2Flib%2Fionic%2Fjs%2Fionic.bu
ndle.js%3A11497%3A5)

Index Page

<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">

<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->

<!-- JQuery Libs (Loading from google api) -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>window.jQuery||document.write('<scrpt:src="../bower_components/jquery.min.js"><\/script>')</script>
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- Lodash Lib -->
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/0.10.0/lodash.min.js"></script>
<!-- Chacing Lib -->
<script src="lib/angular-cache/dist/angular-cache.min.js"></script>
<!-- Google Maps -->
<script src="https://maps.googleapis.com/maps/api/js?key=###&sensor=false"></script>
<script src='https://maps.googleapis.com/maps/api/js?sensor=false'></script> 
<script src="lib/angular-google-maps/dist/angular-google-maps.min.js"></script>

<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>

<!-- your app's js -->
<script src="app/app.js"></script>
<script src="js/controllers.js"></script>
<script src="app/car/car-log-ctrl.js"></script>
<script src="app/home/home-ctrl.js"></script>
<script src="app/settings/settings-ctrl.js"></script>
<script src="app/car_service/car-service-ctrl.js"></script>
<script src="app/login/login-ctrl.js"></script>
<script src="app/location/location-map-ctrl.js"></script>

<script src="app/services/myDriveApi.js"></script>

I got to say that the documentation on this error is very much lacking in the AngularJS documentation.

As for the API key, do I just stick with using the Google map JS api key, or I also need to generate one for android and put it into the android manifest file? Or I only need it if I go cordova route? Which way is better? (So far both seems to be just as bothersome, and in reality this shouldn’t be difficult.)

That error will happen whenever you add a dependency and the declaration is not found. For example, if you add ionic as a dependency but don’t include the ionic javascript files you will get that error. Can you check that the javascript file you are referencing is in the correct directory. Also, maybe check the file to make sure the module is defined?

If you want an alternative API, I have implemented the Google Maps directive by allenhwkim. It was fairly simple to implement and I found the documentation and demos more than enough.

With regards to the API key, on the [Google Maps Signup page] 3 it says: “The Google Maps JavaScript API v3 does not require an API key to function correctly. However, we strongly encourage you to load the Maps API using an APIs Console key which allows you to monitor your application’s Maps API usage.”

I have written a Service for the GoogleAPI, but it took a bit of digging to get it going - I would recommend using leafletjs rather than google mpaps - it seems / feels quicker and is very simple to implement. If you are wanting the GoogleMapsAPI service I have written let me know and I’ll send / upload a copy which you should be able to drop in - you will need your own api key though.

Strange though, cos browser doesn’t trigger this issue. Which is why this is a bit of a pain

I was able to get ngMap impelemtation of google map workin. But I am not entirely convinced with this approach, it feels slow to load on the device. Right now I want to look through all possible options and find the best solution. I want to see all the trade offs between each options

Thank for your advice, appreciated! I will try to check it out and see it for myself. From your perspective, what is the best option? I am making a commercial app for a client, and he wants me to use google map to track locations, directions, and show dealers on the map. For this type of app, leafletjs would be suitable?
I would like to test out GoogleMapAPI too, see how it works, if you wont mind showing your copy :smile:
I got an API key, but apparently you dont have to use it. Doesn’t hurt to though.

Given your requirements it sounds like GooleMaps may be the way to go so that in mind here is the service I implemented: I have included the directives for both item and items, but only the html for items as that seems to be the one you are going for. I think the below should just work out of the bag, but as I said I went to leafletjs eventually so what you are seeing is information from my git history. If you do get this up and running with it showing nearby services (like petrol stations etc) I would be interested in knowing how you achieved it. I have limited time in my evenings owing to a one year old :slight_smile:

angular.module('itemModule.googleMapModule', ['google-maps'.ns()])
    .config(['GoogleMapApiProvider'.ns(), function (GoogleMapApi) {
        GoogleMapApi.configure({
            key: 'your key here',
            v: '3.17',
            libraries: 'weather,geometry,visualization'
        });
    }])

ller",[’$scope’, ‘GoogleMapApi’.ns(), function ($scope, GoogleMapApi) {

    $scope.marker = {
        id: $scope.item.id,
        coords: {
            latitude: 'YOUR LAT',
            longitude: 'YOUR LONG'
        },
        options: { draggable: true },
        show:true,
        title:'SOME TITLE'

    };

    GoogleMapApi.then(function(maps) {

        $scope.options = {

            scrollwheel: false,
            zoomControl: false,
            navigationControl: false,
            mapTypeControl: false,
            scaleControl: false,
            draggable: true,
            disableDoubleClickZoom: true,
            mapTypeId: google.maps.MapTypeId.SATELLITE
           };


        $scope.windowOptions = {
            visible: false
        };

        $scope.onClick = function() {
            $scope.windowOptions.visible = !$scope.windowOptions.visible;
        };

        $scope.closeClick = function() {
            $scope.windowOptions.visible = false;
        };

        $scope.map = {
            center: {
                latitude: 'YOUR LAT',
                longitude: 'YOUR LONG'
            },
            zoom: 12
        };



    });
}])

.directive('itemMap', [function ($scope) {

    function link(scope, elements, attributes, controller) {

    }

    return{
        restrict: 'E',
        scope:{
            item:'=item'
        },
        templateUrl:'templates/itemMap.html',
        controller:'itemMapController'
    }
}])

.controller("itemsMapController",['$scope', '$timeout', 'GoogleMapApi'.ns(), function ($scope, $timeout, GoogleMapApi) {

    $scope.markers = [];

    GoogleMapApi.then(function(maps) {

        $scope.options = {
            scrollwheel: false,
            draggable:true,
            mapTypeId: google.maps.MapTypeId.SATELLITE
             /*zoomControl: false,
            navigationControl: false,
            mapTypeControl: false,
            scaleControl: false,
            draggable: false,
            disableDoubleClickZoom: true*/
        };

        var createMarker = function (item) {
            var marker = {
                id: item.itemnumber,
                coords:{
                    latitude: item.Latitude,
                    longitude: item.Longitude
                },
                show:false,
                title:item.itemname
            };

            marker.onClick = function(){
                marker.show = !marker.show;
            };


            return marker;

        };

        for(var i = 0; i<$scope.items.length; i++)
        {
            $scope.markers.push(createMarker($scope.items[i]));
        }

        $scope.windowOptions = {
            visible: false
        };

        $scope.map = {
            center: {
                latitude: '54.460879',
                longitude: '-3.088620'
            },
            zoom: 9
        };



    });
}])

.directive('itemsMap', [function ($scope) {

    function link(scope, elements, attributes, controller) {

    }

    return{
        restrict: 'E',
        scope:{
            items:'=items'
        },
        templateUrl:'templates/itemsMap.html',
        controller:'itemsMapController'
    }
}])

and then I had this in hillsMap.html

<ui-gmap-google-map ng-if="markers.length==items.length" draggable="true" options="options" center="map.center" zoom="map.zoom">
    <ui-gmap-markers models="markers" coords="'coords'" events="map.markerEvents" icon="'icon'" click="'onClick'">
        <ui-gmap-windows show="'show'">
            <div ng-non-bindable><label style="white-space: nowrap;">{{title}}</label></div>
        </ui-gmap-windows>
    </ui-gmap-markers>
</ui-gmap-google-map>

Using the following to use the items directive:

<hills-map ng-if="hills" data-tap-disabled="true" id="map" class="angular-google-map-container" hills="hills | filter: searchText"></hills-map>

@brandyshea Dear Brandy, I am using same directive, but while testing on DEVICE and open Map page it consumes a lot of memory, The REAL PROBLEM after navigate to any page , it doesn’t destroy the map, so the memory is still NOT FREE, so after many opening to map pages, it leads to APP CRASH.

Any ides?
Thanks

Which device(s) are you using where it’s crashing? Can you provide a codepen or some code of how you’re building the map? I am calling the map on one page and I don’t see this problem on android or iOS.

@brandyshea Device: iPhone 5, and the Crash happend after about 20 times opening the map page.
app.js

angular.module('egraatyApp', ['ionic', 'ngMap', 'ngCordova'])

mapController.js

function MapController($scope) {

$scope.Map ={lat:30.3838383, long:29.483838}


}

map.html

<ion-view ng-controller="MapController" title="{{Map.name}}">
<ion-content>
  
    <div class="angular-google-map-container">

            <map draggable="true"  class="angular-google-map" zoom="17"
                center="[{{Map.lat}}, {{Map.long}}]">

                <marker position="{{Map.lat}}, {{Map.long}}" title="{{Map.name}}">
                    </marker>

              
            </map>
        </div>
</ion-content>

Hmm and you aren’t changing this data dynamically? Have you tried setting the cache for the view to false?

<ion-view view-title="My Page" cache-view="false">
    <ion-content>
        ...
    </ion-content>

Sorry I can’t be more help, I’m not able to reproduce this problem in my app on an iPhone 5. Maybe you can contact allenhwkim? Not sure if it’s related to the directive, though.

After messing around I have went with the option to use Angular Google Map, which is very easy and works well. At least so far. I haven’t found any issues. As far as I understand it has all of the ability of standard google map api, it’s like a wrapper for it.

I got another question to ask though. What should use for geocoding and location services. My client wants it to be a feature where the app knows about the user locations, and if he want to enter a place/area/address the app will geocode it show on the map.

As far as I see it’s not quite clear, or I am not doing a good job at finding it. Any suggestions, demos, or code examples?

I just needed install angular-simple-logger.js, did work for me