Search code examples
angularjspromiseresolvejqvmap

How to resolve a promise for a vector map datasource in Angularjs


Right so I'm fairly new to angular and really enjoying the experience and I'm slowly but successfully running through a few gotchas that keep cropping up, however this one has be stumped.

I'm loading a version of the Jquery Vector map and everything is working a treat. I'm creating the empty object and populating it from my datasource in a format that the map can use to colour code but here is where the problem crops up.

When the map is instantiated, it gets the contents of the object 'ratingobj' however the resource hasn't populated the object by the time its rendered. I can see this in the console log as ratingobj is always empty.

I understand the concept that the resource is a promise and when the data is retrieved it will be populated however what I can't work out is how to get the resource to resolve the resource and get the data prior to the map being loaded!

Please help, any pointers would be great!

Thanks

Here is my resource query in my services:

 .factory('CountryData', ['$resource',
  function($resource){
    return $resource('http://mydatasource/datafeed', {}, {
      query: {
        method:'GET',
        isArray:false,

        }

    })

  }])

Here's the controller

.controller('jqvmapCtrl', ['$scope' ,'CountryData', 'greeting',
function($scope, CountryData, greeting) {

  var ratingobj = {};

  $scope.rating = CountryData.query(function (response){
      angular.forEach(response.record, function(value,key) {
        ratingobj[value.countryISO] = value.countryRating;
        });
    });

    console.log(ratingobj);

  $scope.worldMap = {
    map: 'world_en',
    backgroundColor: null,
    color: '#ffffff',
    hoverOpacity: 0,
    hoverColor: '#C2C2C2',        
    selectedColor: '#666666',
    enableZoom: true,
    showTooltip: true,
    values: ratingobj,
    scaleColors: ['#C4FFFF', '#07C0BB'],
    normalizeFunction: 'polynomial',
  };

}
]);

This is my main app file with the route

  .when('/countries/map', {
    templateUrl: 'views/countries/map.html',
controller: 'jqvmapCtrl',

  })

Solution

  • how to get the resource to resolve the resource and get the data prior to the map being loaded

    There are two ways how to accomplish that.

    1. Delay rendering of the map widget until the data is loaded. Add ng-if="worldMap" to the element holding your map, for example

    <div id="vmap" ng-if="worldMap"></div>
    

    See the following SO answer for more details: https://stackoverflow.com/a/22510508/69868

    2. Delay rendering of the whole view until the data is loaded.

    Extend the route definition with a resolve block.

    .when('/countries/map', {
      templateUrl: 'views/countries/map.html',
      controller: 'jqvmapCtrl',
      resolve: {
        ratingobj: function(CountryData) {
          return CountryData.query().$promise
            .then(function(response) {
              var ratingobj = {};
              angular.forEach(response.record, function(value,key) {
                ratingobj[value.countryISO] = value.countryRating;
              });
              return ratingobj;
            });
        }
      }
    })
    

    Modify the controller to get ratingObj injected instead of CountryData:

    .controller('jqvmapCtrl', ['$scope' ,'ratingobj', 'greeting',
    function($scope, ratingobj, greeting) {
      console.log(ratingobj);
    
      $scope.worldMap = {
        map: 'world_en',
        backgroundColor: null,
        color: '#ffffff',
        hoverOpacity: 0,
        hoverColor: '#C2C2C2',
        selectedColor: '#666666',
        enableZoom: true,
        showTooltip: true,
        values: ratingobj,
        scaleColors: ['#C4FFFF', '#07C0BB'],
        normalizeFunction: 'polynomial',
      };
    }
    ]);
    

    See the following SO answer for more details: https://stackoverflow.com/a/16288468/69868