Reputation: 847
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
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
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
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