27

I am considering migrating from backbonejs to angularjs.

In backbone I am able to initialize a view at which point I create an instance of google map. I can then pan/zoom/etc and switch between views and not lose the current state of the map.

Given the following using angularjs:

layout.html

<body>
  <div class="container-fluid" ng-view></div>

map.html

<div id="map_canvas" ng-controller="MapCtrl"></div>

I was able to create a directive to render a map just fine. Problem is that it reloads the map each time I switch back to the map view.

<map></map>

So from what I am learning about Angular, I figured I would create a MapController and initialize the map there. No success.

Bottom line is I need to async-init a google map and push data to it locally or remotely AND be able to navigate the app without RELOADING the map from scratch each time.

Can someone suggest the correct approach?

Thank you :)

Attempt Per Andy Joslin suggestion:

In app.js:

// Generated by CoffeeScript 1.3.3
(function() {
  "use strict";

  angular.module("ofm", ["ofm.filters", "GoogleMaps", "ofm.directives"]).config([
    "$routeProvider", "$locationProvider", function($routeProvider, $locationProvider) {
      $routeProvider.when("/", {
        templateUrl: "partials/home"
      }).when("/map", {
        templateUrl: "partials/map",
        controller: MapCtrl
      }).otherwise({
        redirectTo: "/"
      });
      return $locationProvider.html5Mode(true);
    }
  ]);

}).call(this);

In services.js:

angular.module('GoogleMaps', []).
  factory('wasMapInitialized', function() {
    console.log("inside service");
    var maps = 0;

    if (!maps) {
      maps += 1;
      return 0;
    } else {
      return 1;
    }
  });

In controllers.js:

function MapCtrl($scope) {
  if (!GoogleMaps.wasMapInitialized()) {
    var lat = 46.87916;
    var lng = -3.32910;
    var map_id = '#map';
    initialize(map_id, lat, lng);
  }
  function initialize(map_id, lat, lng) {
    var myOptions = {
      zoom : 8,
      center : new google.maps.LatLng(lat, lng),
      mapTypeId : google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map($(map_id)[0], myOptions);
  }
}

In map.html

#map
<div ng-controller="MapCtrl"></div>

I get Error: Unknown provider: GoogleMapsProvider <- GoogleMaps

5
  • +1. Would like to know the answer as well. Commented Jun 25, 2012 at 3:15
  • 1
    I created a project angular-google-maps with ongoing improvements. See live version Commented Jun 27, 2012 at 22:41
  • Great, already on my watch list. :) Commented Jun 28, 2012 at 1:27
  • 1
    @LarryEitel you should accept Andy's answer Commented Jul 11, 2012 at 10:33
  • I can't get this to work in the slightest way with AngularJS 1.0.8 and Google Maps API v3. Commented Nov 14, 2013 at 6:12

4 Answers 4

19

Since views create and destroy controllers when the view changes, you want your maps data to persist somewhere else. Try creating a GoogleMap service which will store the data.

myApp.factory('GoogleMaps', function() {
  var maps = {};

  function addMap(mapId) {
    maps[mapId] = {};
  }
  function getMap(mapId) {
    if (!maps[mapId]) addMap(mapId);
    return maps[mapId];
  }

  return {
    addMap: addMap,
    getMap: getMap
  }
});

function MyController($scope, GoogleMaps) {
  //Each time the view is switched to this, retrieve supermanMap
  $scope.map = GoogleMaps.getMap('supermanMap');

  $scope.editMap = function() {
    $scope.map.kryptonite = true;
  };
}

If you don't like this solution, there are some other ways to do it too.

Sign up to request clarification or add additional context in comments.

6 Comments

Could you shortly outline the other options (just naming them)? Thank you.
You could create the map in $rootScope, which is never destroyed, and have child scopes inherit it. You could also not use ng-view so the scopes and dom elements aren't created destroyed, but instead are shown and hidden, but you'd have to roll your own routing system. You could also create a maps thing which is just a plain old JavaScript object outside angular that your angular controllers reference (but this is really just a poor way of doing a service)
Andy, Very nice of you to suggest some ideas. I am so green at Angular. Any chance you can stub out an example? I am stuck in the mud and spinning my wheels. Thank you :)
You're initializing your service wrong. Here's an example JSFiddle: jsfiddle.net/mL34U
Andy, Thank you very much. Your suggestion worked great. I will post actual code used ASAP.
|
1

This is what I am doing in Backbone to keep the view instead of destroying it. Suppose you have a div with id="container" and your router have the corresponding routes.

routes: {
    "":"home",
    "map": "showMap"
},

showMap: function() {
    $("#container").children().detach();
    if(!this.mapView) {
        this.mapView = new MapView(); 
        this.mapView.render();
    }
    $("#container").html(this.mapView.el);
}

1 Comment

Thank you Jerry however, your solution is in backbone rather than angularjs.
0

Here's my solution for using the maps api with Angularjs routeProvider: in your index you have to add:

angular-google-maps.min.js and lodash.min.js

in application.js:

(function() {

var app = angular.module("myApp", ["ngRoute", "uiGmapgoogle-maps"]);


app.config(function(uiGmapGoogleMapApiProvider) {
    uiGmapGoogleMapApiProvider.configure({
        key: 'YOUR KEY HERE',
        v: '3.17',
        libraries: 'weather,geometry,visualization'
    });
});

app.config(function($routeProvider) {
    $routeProvider
        .when("/home", {
            templateUrl: "home.html",
            controller: "HomeController"
        })
        .when("/workwith", {
            templateUrl: "workwith.html",
            controller: "WorkwithController"
        })




    .otherwise({
        redirectTo: "/home"
    });

});

})();

Last But not least in your controller:

(function() {
var app = angular.module("myApp");
var MyController = function($scope, $http, $log, $location, $routeParams, uiGmapGoogleMapApi) {
    $log.info("MyController");
    $log.info($routeParams);

    // Define variables for our Map object
    var areaLat = 44.2126995,
        areaLng = -100.2471641,
        areaZoom = 3;

    uiGmapGoogleMapApi.then(function(maps) {
        $scope.map = {
            center: {
                latitude: areaLat,
                longitude: areaLng
            },
            zoom: areaZoom
        };
        $scope.options = {
            scrollwheel: false
        };
    });    
 };
app.controller("MyController", MyController);

})();

Comments

0

Hi Larry Eitel and everyone, I have the following approach:

First, we need to create some global variables:

var mapGlobal, flag=0, CurrentmapNode;

Then in Controller:

    function MapCtrl($scope) {
    var lat = 46.87916;
    var lng = -3.32910;
    var map_id = '#map';

     if (flag==0)
       initMap(mapId, lat, lng);
     else
       reinitMap(mapId);

  function initMap(map_id, lat, lng) {
    var myOptions = {
      zoom : 8,
      center : new google.maps.LatLng(lat, lng),
      mapTypeId : google.maps.MapTypeId.ROADMAP
    };
    mapGlobal = new google.maps.Map($(map_id)[0], myOptions);

    if (typeof mapGlobal != 'undefined')
       flag=1;
  }

  function reinitMap(mapId){
     $(mapId)[0].append(CurrentmapNode);
   }

   $scope.$on("$destroy", function(){
        CurrentmapNode = mapGlobal.getDiv(); //save current map in an auxiliar variable
   });

}

The "on destroy" function saves current map state in another global variable, then, when view is recreated, we don't need to create another map instance.

Creating another map instance can cause memory leak and increase Google maps API usage each time view is recreated.

Best regards

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.