Kiran Madipally
Kiran Madipally

Reputation: 847

Best way to pre-load data from using $http in a service in AngularJs

I am trying to create a service which first loads some data by making an AJAX call using $http.

I am looking at something like:

app.factory('entityFactory', function() {
    var service = {};

    var entities = {};

    // Load the entities using $http

    service.getEntityById(entityId)
    {
        return entities[entityId];
    }

    return service;
});

app.controller('EntityController', ['$scope', '$routeParams', 'entityFactory', function($scope, $routeParams, entityFactory) {
    $scope.entity = entityFactory.getEntityById($routeParams['entityId']);
}]);

I want to make sure that the entities is loaded fully before I return the entity using getEntityById.

Please let me know what would be the right way to do this? One way I know would be to make a synchronous AJAX call, but is there anything better? Can promises be used in this case in a better way?

Upvotes: 1

Views: 1369

Answers (3)

Michal Charemza
Michal Charemza

Reputation: 26982

Passing in a callback or calling $q.defer(), are often signs that you're not taking advantage of promise chaining. I think a reasonable way to do what you're asking is as follows.

app.factory('entityFactory', function($http) {
  var service = {};

  var _entitiesPromise = $http({method: 'GET', url: '/getData'});

  service.getEntityById = function(entityId) {
    return _entitiesPromise.then(function(results) {
      return results.data.entities[entityId];
    });
  };

  return service;
});

app.controller('EntityController', ['$scope', '$routeParams', 'entityFactory', function($scope, $routeParams, entityFactory) {
  entityFactory.getEntityById($routeParams['entityId']).then(function(entity) {
    $scope.entity = entity;
  }, function() {
    // Can still do something in case the original $http call failed
  });
}]);

where you only cache the promise returned from $http.

Upvotes: 0

Kiran Madipally
Kiran Madipally

Reputation: 847

Tried using $q to check if service is initialized. Clean enough for me, any other methods are welcome :).

app.factory('entityFactory', function($q, $http) {
    var service = {};

    var _entities = {};
    var _initialized = $q.defer();

    $http({method: 'GET', url: '/getData'})
        .success(function(data, status, headers, config) {
            if (data.success)
            {
                _entities = data.entities;
            }

            _initialized.resolve(true);
        })
        .error(function(data, status, headers, config) {
            _initialized.reject('Unexpected error occurred :(.');
        });

    service.getEntityById(entityId)
    {
        return entities[entityId];
    }

    service.initialized = _initialized.promise;

    return service;
});

app.controller('EntityController', ['$scope', '$routeParams', 'entityFactory', function($scope, $routeParams, entityFactory) {
    entityFactory.initialized.then(function() {
        $scope.entity = entityFactory.getEntityById($routeParams['entityId']);
    });
}]);

Upvotes: 1

tymeJV
tymeJV

Reputation: 104775

You can utilize callbacks within factories to store the data on the first call and then receive the data from the service on every subsequent call:

app.factory('entityFactory', function() {
    var service = {};

    var entities = null;

    // Load the entities using $http
    service.getEntityById(entityId, callback)
    {
        if (entities == null) {
            $http(options).success(function(data) {
                entities = data;
                callback(data);
            });
        } else {
            callback(entities);
        }
    }

    return service;
});

And then you can use this:

entityFactory.getEntityById(id, function(entities) {
    //console.log(entities);
});

Upvotes: 0

Related Questions