Reputation: 1355
I am attempting to write a directive to resolve promises and add data to the scope so that I can lazily load data into child elements from an API.
Through console.logging I am certain that I am resolving the promise and getting my expected data, but nothing updates on the page. I am assuming that dynamically adding to the scope from inside a directive is causing my problem.
The directive seems fairly trivial and I know that the promise is getting resolved:
app.directive('resolver', () => {
return {
restrict: "AEC",
scope: {
outName: "@",
promise: "&",
defaultVal: "="
},
link: function ($scope, element, attrs) {
var promise = $scope.promise,
outName = $scope.outName || 'myPromise',
defaultVal = $scope.defaultVal || {};
$scope[outName] = defaultVal;
promise().then(data => {
$scope[outName] = data;
});
}
}
});
I was hoping that this would let me do something like the following:
<li class="company-entry" ng-repeat="company in currentFeed.companies" resolver promise="getPreview(company.companyId)" out-name="profile" default-val="{name:'Loading...',description:'',images:[],sources:[]}">
...
<a ui-sref="company.feed({ id: company.companyId })" class="company-name">{{ profile.name || 'foo' }}</a>
</li>
Firstly, I have profile.name || 'foo'
in order to test if the default-val part of my code would work; since it stays at foo, not even the default value gets placed into profile
.
Secondly, after the promise is resolved, I should be setting profile
to the data, but the page does not updating.
Adding a $scope.$apply()
causes me to get rootscope update already in progress errors.
Is there any way to accomplish what I am trying to do?
Upvotes: 4
Views: 634
Reputation: 276306
I would solve this differently. Instead of building this into a directive you can easily produce a thenable that automatically unwraps just like ngResource does.
Let's consider an example: You have an array you need to fetch online with a getArray()
function which returns a promise and makes an http request.
Normally you do:
getArray().then(function(result){
$scope.data = result;
});
Which I assume you're trying to avoid because it's a lot to write if everything in your scope is like this. The trick promises used to use and ngResource still uses in Angular is the following:
For example, our getArray()
could look something like:
function getArray(){
var request = $http(...); // actual API request
var result = []
result.then = request.then; // make the result a promise too
result.then(function(resp){
// update _the same_ object, since objects are passed by reference
// this will also update every place we've send the object to
resp.data.forEach(function(el){ result.push(el); });
});
return result;
}
Now if you call getArray()
and assign the result to a scope variable, whenever the promise resolves it will update the value.
Upvotes: 3