1

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?

3 Answers 3

1

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']);
    });
}]);
Sign up to request clarification or add additional context in comments.

Comments

0

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);
});

Comments

0

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.

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.