Reputation: 1847
I am using ui-router 0.2.0 (I know it is an older version but we are locked on Angular 1.0.8 for various reasons) and trying to use resolve: {}
to ensure controllers are dealing with concrete data and not eventual data (promises).
I currently have the following:
resolve: {
items: ['listSvc', function (listSvc) {
console.log('resovling items');
var items = listSvc.getItems();
items.then(function () {
console.log('horray!');
});
return items;
}]
}
Items contains about eight items right now just with a title and my view just does a ng-repeat
and displays each title.
The controller:
App.controller('MyCtrl', ['$scope', 'items', function ($scope, items) {
console.log('MyCtrl');
$scope.items = items;
}]);
The view:
<div>
<h1>Items</h1>
<div data-ng-repeat="item in items">
{{ item.Title }}
</div>
</div>
Sometimes I am seeing approximately 2 seconds elapse between when I see 'horray!' and the resulting view. Other times I see 'horray!' but never transition to the expected view. How do I troubleshoot/fix this?
My listSvc is also using Q rather than $q if that matters.
Edit: moved question to the bottom for clairity
Edit:
While the selected answer worked for all my jsbin testing and is correct according to all documentation I have found. This is what fixed my actual problem, I know its nasty and awful, but it is the only thing I could get to work for our application. In the example below, my listSvc is using Q
resolve: {
items: ['listSvc', 'currentUser', '$q', '$rootScope', function (listSvc, currentUser, $q, $rootScope) {
console.log('my => items');
var deferred = $q.defer();
listSvc.setUser(currentUser);
listSvc.getMyItems().then(function (myItems) {
deferred.resolve(myItems);
return myItems;
}).fin(function () {
$rootScope.$apply();
});
return deferred.promise;
}]
}
Upvotes: 1
Views: 987
Reputation: 276596
My listSvc is also using Q rather than $q if that matters.
Yes, yes it does. This is your problem.
Q is a much more complete promise implementation than $q
, it has a lot more features. However $q
integrates into the AngularJS digest cycle.
My suggestion would be instead of using tricks like a scope apply in a .finally
uniformally - use $q.when(prom)
which is a utility method that takes a thenable (generic promise) and turns it into a trusted $q
promise. If you don't have anything that runs in $q, you'll still need to call $rootScope.$apply()
at the end of your promise chain.
If that doesn't work, you can simply add
.finally(function(){ $scope.apply(); })
To the end of your promise chains.
Most good promise libraries implement the A+ specification that allows clean and simply assimilation of one kind of promise into another. Since both Q and $q are Promises/A+ complaint - this means you can interop between Q and $q very easily (since they have similar .then semantics):
when(value) - Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted.
In your case - something like:
var items = $q.when(listSvc.getItems()); // don't forget to inject $q
Or wrap it in a when
at any other point in the chain.
Upvotes: 2