Обещания: переход к следующей функции ошибки Просто нужно перестроить ошибку.
Почему обетованная ссылка не выполняет функцию ошибки при шпионаже на нее?
Имея две кнопки, возвращающие (вызывающие) одно и то же обещание, один выполняется нормально ($ scope.expected() - кнопка отображает красный цвет), другой переходит к функции успеха ($ scope.notExpected() - кнопка отображается зеленым), и это не ожидается.,
Современное решение состоит в том, чтобы обернуть другое обещание;
var app = angular.module('thenApp', []);
function ThenCtrl($scope, thenService, $q) {
$scope.expected = function() {
return thenService.doIt()
.then(function() {
console.log('was a success');
});
};
$scope.notExpected = function() {
return thenService.doIt()
.then(function() {
console.log('was a success');
}, function() {
console.log('has failed');
});
};
$scope.solution = function() {
var deferred = $q.defer();
thenService.doIt()
.then(function() {
deferred.resolve();
console.log('was a success');
}, function() {
deferred.reject();
console.log('has failed');
});
return deferred.promise;
};
}
app.controller('ThenCtrl', ThenCtrl);
var CLICK_EVENT = 'click';
var TIMEOUT_TO_END_ANIMATION = 1000;
var SUCCESS_CLASS = 'btn-success success';
var FAIL_CLASS = 'btn-error error';
var LOADING_CLASS = 'loading';
/**
* Inspiration from https://github.com/johannesjo/angular-promise-buttons
* @param $parse
* @param $timeout
* @returns {{scope: {promise: string, stateRedirect: string}, link: link}}
*/
function btnLoader($parse, $timeout) {
return {
restrict: 'A',
require: '?ngClick',
scope: true,
link: function(scope, el, attrs) {
el.addClass('btn-load');
var promiseWatcher;
// we need to use evalAsync here, as
// otherwise the click or submit event
// won't be ready to be replaced
scope.$evalAsync(function() {
var cb = $parse(attrs.ngClick);
function buttonLoader() {
// Make sure we run the $digest cycle
scope.$apply(function() {
var promise = cb(scope.$parent, {
$event: CLICK_EVENT
});
// only init watcher if not done before
if (!promiseWatcher) {
// watch promise to resolve or fail
promiseWatcher = scope.$watch(function() {
return promise;
}, function(nVal) {
// for regular promises
if (nVal && nVal.then) {
el.unbind(CLICK_EVENT);
el.addClass(LOADING_CLASS);
el.removeClass(SUCCESS_CLASS);
el.removeClass(FAIL_CLASS);
nVal.then(function() {
// promise was a success
el.addClass(SUCCESS_CLASS);
if (attrs.alwaysBind) {
el.bind(CLICK_EVENT, buttonLoader);
}
}, function() {
// promise was a fail
el.addClass(FAIL_CLASS);
el.bind(CLICK_EVENT, buttonLoader);
}).finally(function() {
el.removeClass(LOADING_CLASS);
promiseWatcher();
promiseWatcher = null;
$timeout(function() {
el.removeClass(SUCCESS_CLASS);
el.removeClass(FAIL_CLASS);
}, TIMEOUT_TO_END_ANIMATION);
});
}
});
}
});
}
// unbind original click event
el.unbind(CLICK_EVENT);
// rebind, but this time watching it return value
el.bind(CLICK_EVENT, buttonLoader);
});
}
};
}
app.directive('btnLoader', btnLoader);
function thenService($q, $timeout) {
thenService.doIt = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.reject(null);
}, 500);
return deferred.promise;
};
return thenService;
}
app.factory('thenService', thenService);
.loading {
background: yellow !important;
}
.btn-error {
background: red !important;
}
.btn-success {
background: green !important;
}
.btn {
margin-bottom: 20px;
border: 1px solid rgba(0, 0, 0, 0.3);
background: white;
width: 250px;
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
text-transform: uppercase;
}
.btn:hover {
background: lightgray;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="thenApp" ng-controller="ThenCtrl">
<p>
Button action does not spy on then error function.
</p>
<div class="btn" btn-loader="" always-bind="true" ng-click="expected()">
As expected
</div>
<p>
Button action spies on then error function.
</p>
<div class="btn" btn-loader="" always-bind="true" ng-click="notExpected()">
Not expected
</div>
<p>
Solution for spying on then error function.
</p>
<div class="btn" btn-loader="" always-bind="true" ng-click="solution()">
Solution
</div>
</div>
Ошибка должна быть сброшена.
someService.call().then(function(){
// success
}, function(e){
// error
throw e;
})