I am working at simple application for Decision Support Systems classes. I’ve decided to write it as a single page application with AngularJS. Yesterday I had a problem with angular.bootstrap method, thought the solution is pretty simple I’ve decided to put it here because I know that my memory tends to be volatile. Ok then, let’s explain what was the problem.
I use ui-map directive in application I mentioned above to work with Google Maps API. This directive requires to load angular application after Google Maps API is ready to use. That’s why I have to use angular.bootstrap method (I’ve noticed it’s not a common approach) instead of ng-app directive.
When I’ve used this approach for the first time the map was loaded correctly, but rest of the application didn’t work. In other case, when I’ve tried ng-app instead of angular.bootstrap, the map wasn’t loaded but the other parts worked as I expected. I gave the broken code I’ve been working with below.
app.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<!DOCTYPE html> <html lang="en"> <head> <style type="text/css"> .map-canvas { height: 500px; } </style> </head> <body> <nav> <form> <div> <div ng-controller="suggestingCities"> <label for="sourceLocation">Startup city</label> <select class="form-control" id="sourceLocation" ng-model="selected" ng-options="city.name for city in cities"> <option value="">--Select City--</option> </select> </div> </div> </form> </nav> <section id="map" ng-controller="map"> <div ui-map="mapWithTheRoute" ui-options="mapOptions" class="map-canvas"></div> </section> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.js"></script> <script type="text/javascript" src="event.js"></script> <script type="text/javascript" src="ui-map.js"></script> <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=onGoogleMapsApiReady"></script> <script type="text/javascript" src="script.js"></script> </body> </html> |
app.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
function onGoogleMapsApiReady() { angular.bootstrap(document.getElementById("map"), ['fancyTraveler']); } var app = angular.module('fancyTraveler', ['ui.map']); app.controller('suggestingCities', function ($scope, citiesRepository) { $scope.selected = undefined; citiesRepository.listOfAvailableCitites().then(function (data) { $scope.cities = data; }); }); app.controller('map', ['$scope', function ($scope) { $scope.mapOptions = { center: new google.maps.LatLng(35.784, -78.670), zoom: 15, mapTypeId: google.maps.MapTypeId.ROADMAP }; }]); app.factory('citiesRepository', function citiesRepository($http) { var citiesPath = 'availableCities.txt'; return { listOfAvailableCitites: function() { return $http.get(citiesPath).then(function(result) { return result.data; }); } }; }); |
It took me some time to find the solution. I have been injecting angular application into “map” element instead of the whole body! It was the reason of partially working scenario. All I had to do was a slight change in an invocation of application.bootstrap. Now the application is initialized in this way:
1 2 3 |
function onGoogleMapsApiReady() { angular.bootstrap(document.getElementsByTagName("body"), ['fancyTraveler']); } |
And it works correctly. I’ve prepared a simple working demo on plunker, which is available here. Be aware that manually refresh the preview might be necessary to run it.
After I had found the solution I was wondering why it took me more time to resolve the problem than it should. The answer was simple as well. I’ve used copy-paste method for the initialization part directly from github and I’ve made an assumption that it works and there is nothing to break. As you can see it’s a great example of why you should avoid copy-paste during development. It turns off thinking and brings the risk that you will spend more time for resolving bugs than in case you rewrite the code by hand. I would like you to remember this from today:
Copy-paste method is an evil and you should avoid it while you do coding.
Because as I showed, it can really run you into troubles.