Следите за функцией ошибки обещания, прерывая ссылку на обещание

0

Найденное решение

Обещания: переход к следующей функции ошибки Просто нужно перестроить ошибку.

Почему обетованная ссылка не выполняет функцию ошибки при шпионаже на нее?

Имея две кнопки, возвращающие (вызывающие) одно и то же обещание, один выполняется нормально ($ 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>

Теги:
promise

1 ответ

0

Ошибка должна быть сброшена.

someService.call().then(function(){
  // success
}, function(e){
  // error
  throw e;
})

Обещания: перейти к следующей функции ошибки

Ещё вопросы

Сообщество Overcoder
Наверх
Меню