I've found out the hard way that when you two-way bind a promise, angular resolves the promise for you and does bind the actual promise. My question is then, how would one handle a rejected promise?
My particular case is that I have a directive where I two-way-bind a promise from my controller. My controller expects the directive to handle rejection of that promise, since the error would need to be displayed on the DOM.
In my directive I'd expect my bound variable to be a promise, but instead I get the resolved value of that promise. Annoying, but, not terrible.
The issue is when that promise is rejected, the directive has no way of knowing.
See this plunker as an example:
http://plnkr.co/edit/m0cOqFhx6TNrDxTbr9Qx?p=preview
How can I handle the promise rejection in my directive?
Thanks, Roy
I have three suggestions - none which are perfect, but they all work:
Create a getter method that returns the promise and bind this method to the directive using &
Bind the deferred object instead of the promise (ugly)
Broadcast an event when the promise resolves / gets rejected
I've created a plunker with all the suggestions: http://plnkr.co/edit/jsA0PwpQm0xycLclkBU3?p=preview
app.controller('MainCtrl', function($scope,$q,$timeout) {
var deferred = $q.defer();
$scope.promise = deferred.promise;
$scope.deferred = deferred;
$scope.getPromise = function(){
return deferred.promise;
}
$scope.promise.then(function(msg){
$scope.$broadcast('promiseThen',{rejected:false,msg:msg});
},function(msg){
$scope.$broadcast('promiseThen',{rejected:true,msg:msg});
});
$timeout(function(){deferred.reject('No reason...');},1500)
});
<div promise-test deferred="deferred" get-promise='getPromise()' ></div>
app.directive('promiseTest',function(){
return {
template:'<div>m1: {{m1}}<br>m2: {{m2}}<br>m3: {{m3}}</div>',
scope:{getPromise:'&',deferred:'='}
,link:function(scope,el,attrs){
scope.m1 = scope.m2 = scope.m3 = 'Waiting...';
scope.getPromise().then(function(msg){
scope.m1 = 'Resolve getPromise: '+msg;
},function(msg){
scope.m1 = 'Reject getPromise: '+msg;
})
scope.deferred.promise.then(function(msg){
scope.m2 = 'Resolved deferred.promise: '+msg
},function(msg){
scope.m2 = 'Rejected deferred.promise: '+msg
});
scope.$on('promiseThen',function(ev,val){
if(val.rejected){
scope.m3 = 'Rejected promiseThen: '+val.msg
}else{
scope.m3 = 'Resolved promiseThen: '+val.msg
}
})
}
}
})
The success and error callbacks can be passed as parameters using &
.
In this option, the controller is responsible for adding the callbacks to .then
.
app.controller('MainCtrl', function($scope,$q,$timeout) {
var deferred = $q.defer();
$scope.register = function(callback, errback) {
deferred.promise.then(callback, errback);
}
$timeout(function(){deferred.reject('No reason...');},1500)
});
app.directive('promiseTest',function(){
return {
template:'<div>m1: {{m1}}',
scope:{register:'&'},
link:function(scope,el,attrs){
scope.m1 = 'Waiting...';
scope.register({
success: function(msg){
scope.m1 = 'Resolve getPromise: '+msg;
},
errback: function(msg){
scope.m1 = 'Reject getPromise: '+msg;
}
});
}
}
})
<div promise-test register='register(success, errback)' ></div>
plunkr
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With