Reputation: 1665
I am having similar factory with $http call inside like following:
appModule = angular.module('appModule', []);
appModule.factory('Search', function($rootScope, $http) {
var Search;
Search = {};
Search.types: ["bacon"];
Search.pastEvents = null;
$http.get('api/highlights').success(function(response) {
return Search.pastEvents = response.data;
});
return Search;
});
var notes_module = angular.module('notes', []);
notes_module.config(['$routeProvider', function ($routeProvider) {
var notes_promise = ['Notes', '$route', 'Search', function (Notes, $route, Search) {
//suspect that Search not having pastEvents ready in time of calling index method
//Notes resource
return Notes.index({subject_id: 1 }, Search);
}];
$routeProvider.when('/notes', {
templateUrl:'index.tpl.html',
controller:'NotesCtrl',
resolve:{
notes: notes_promise,
}
});
}]);
Should i care about when data from $http call is ready and when this factory is initialized/injected? Will pastEvents be ready? If i should care how do i do?
I suspect that Search object not having pastEvents ready in time of calling index method of Notes resource.
Upvotes: 4
Views: 7065
Reputation: 35829
It depends:
If you immediately place in in $scope
to be used e.g. in a ng-repeat
, then no.
If you need in another function in your controller, then yes. E.g. if you use your pastEvents
in a filter function on your controller. In such case it is best to keep all manipulations internally within your service and use $q
to solve the asynchronuous riddle.
(This is just an example)
appModule.factory('sharedApplication', function($rootScope, $http, $q) {
var deferred = $q.defer();
$rootScope.$on('data:loaded', function(e, data) {
deferred.resolve(data);
});
return {
getApp: function(filter) {
if (!filter) { filter = function() { return true; } }
var filtered = {};
deferred.promise.then(function(data) {
filtered.pastEvents = _.filter(data, filter);
};
return filtered;
}
};
});
A little explanation. The data arrives with an event in the service. At that point getApp()
may already have been called. But that doesn't matter, because $q
will make sure that the data will only be filtered when it later arrives. The controller doesn't need to know that, as long as it does not try to do things like:
$scope.app = service.getApp();
for(var i = 0; i < $scope.app.pastEvents.length; i++) {
...
}
If you really need to evaluate the content in the controller, use $scope.$watch()
, e.g:
$scope.$watch('app', function(value) {
...
}, true);
Edit:
In my opinion, in your situation Search
is not yet resolved when you use it in your $routeProvider
:
Notes.index({subject_id: 1 }, Search)
So try to resolve Search
instead and use your Notes
resource in your controller.
You need to return a promise in your Search
service. Two options:
$q example:
appModule.factory('Search', function($rootScope, $http, $q) {
var deferred = $q.defer();
$http.get('api/highlights').success(function(response) {
deferred.resolve({
type: ["bacon"],
pastEvents: response.data)};
});
return deferred.promise;
});
Upvotes: 5