Разрешить обещание до изменения состояния UI-Router

Я использую ui-router и дополнения ui-router

$scope.$on('$transitionStart', function (e, $transition$) {
    var params = {id:1};
    factory.webService(params)
        .success(function (data) {
            if (data.d == "Expired") {//Inspects the application session
                //Stops the state request and sents you to the login screen
                e.preventDefault();
                location.href = "login.html";
            }
            else if (data.d == "NotAllowed") {
                //Stops the state request and keeps you on the state you already are
                e.preventDefault();
            } else {
                //Proceed to load the requested state
            }
        })
        .error(function (data, status) {
            alert(data.Message);
        });
});

Мне нужно разрешить часть успеха до загрузки $stateChangeStart, и я не могу понять, как это сделать.

Есть ли способ достичь этого?

РЕДАКТИРОВАТЬ

Итак, у меня есть такой код

.state('myState', {
        url: "/myState",
        templateUrl: 'views/template.html',
        controller: 'ctrlTemplate',
        viewId: 99,
        resolve: {
            fn: function ($stateParams, myFactory) {
                myFactory.checkSession({viewId:99})
                .then(function onSuccess(response) {
                    var data = response.data;
                    if (data.d == "Expired") {
                        throw "Expired";
                    }
                    else if (data.d == "NotAllowed") {
                        throw "NotAllowed";
                    } else {
                        //RETURN to chain data
                        return data;
                        //Proceed to load the requested state
                    }
                })
                .catch(function (response) {
                    //e.preventDefault();
                });
            }
        }
    })

Функция $http .then все еще обрабатывается ПОСЛЕ $stateChangeStart и $transitionStart, и новое состояние уже загружается. Я вижу, как это происходит в отладчике консоли браузера.

Пожалуйста, помогите.


person Jozkee    schedule 02.02.2017    source источник


Ответы (2)


мне нужно дождаться ответа $http и поймать его в функции .success

Метод .success ( устарело и теперь удалено из AngularJS 1.6) не может отклонить обещание, но метод .then способен преобразовать успех в отклонение:

var promise = factory.webService(params)
    //.success(function (data) {
    .then( function onSuccess(response) {
        var data = response.data;
        if (data.d == "Expired") {
            //THROW to create a rejected promise
            throw "Expired";
            /*
            //Inspects the application session
            //Stops the state request and sents you to the login screen
            e.preventDefault();
            location.href = "login.html";
            */
        }
        else if (data.d == "NotAllowed") {
            //THROW to create a rejected promise
            throw "NotAllowed";
            /*
            //Stops the state request and keeps you on the state you already are
            e.preventDefault();
            */
        } else {
            //RETURN to chain data
            return data;
            //Proceed to load the requested state
        }
    })
    //.error(function onError(data, status) {
    .catch( function(response) {
        var data = response.data;
        var status = response.status;
        alert(data.Message);
        //THROW to chain rejection
        throw data.Message;
    });
});

Используя оператор return или throw, новое производное обещание создается из ответа, разрешенного методами .then или .catch в httpPromise.

Когда функция разрешения состояния пользовательского интерфейса получает отклоненное обещание, изменение состояния прерывается.


ОБНОВИТЬ

Итак, у меня есть такой код...

    //ERRONEOUS
    resolve: {
        fn: function ($stateParams, myFactory) {
            myFactory.checkSession({viewId:99})
            .then(function onSuccess(response) {
                var data = response.data;
                if (data.d == "Expired") {
                    throw "Expired";
                }

Я не могу понять, почему бросок не вызывает $stateChangeError.

Функция распознавателя должна вернуть обещание маршрутизатору:

    resolve: {
        fn: function ($stateParams, myFactory) {
          //vvvvvv RETURN the promise
            return myFactory.checkSession({viewId:99})
            .then(function onSuccess(response) {
                var data = response.data;
                if (data.d == "Expired") {
                    throw "Expired";
                }

Когда функция пропускает оператор return, функция возвращает значение undefined. В этом случае маршрутизатор считает это успешным со значением undefined.

Также метод .catch ошибочен

    //ERRONEOUS   
          })
            .catch(function (response) {
                //e.preventDefault();
            });

Когда обработчик отклонения метода .catch пропускает оператор return (или throw), функция возвращает значение undefined. Это преобразует отклонение в успешное обещание, которое разрешается со значением undefined.

      //CORRECT   
            })
            .catch(function (response) {
                //THROW to chain rejection
                throw response;
                //e.preventDefault();
            });

Эмпирическое правило функционального программирования: всегда что-то возвращать.

В случае успеха обещания и отклонения: всегда return или throw что-то.

person georgeawg    schedule 03.02.2017
comment
Привет, georgeawg, благодаря Тому и вам, мне удалось получить ответ до изменения состояния, но теперь я не могу понять, почему бросок не вызывает $stateChangeError - person Jozkee; 04.02.2017
comment
Функция разрешения не возвращает производное обещание. См. дополнительный ответ. - person georgeawg; 04.02.2017

Да, есть более элегантный способ сделать это: разрешить с помощью ui-router

Пример:

$stateProvider.state('users.profile', {
  url: '/:id',
  templateUrl: 'views/users.profile.html',
  controller: 'UsersController',
  resolve: {
    user: function($stateParams, UserService) {
      return UserService.find($stateParams.id);
    },
    tasks: function(TaskService, user) {
      return user.canHaveTasks() ?
        TaskService.find(user.id) : [];
    }
  }
});

Прочтите следующую статью о Расширенная маршрутизация и разрешение для более подробной информации.

person Tome Pejoski    schedule 02.02.2017
comment
Я забыл упомянуть, фабрика возвращает $http, поэтому мне нужно дождаться ответа $http и поймать его в функции успеха, возможно, я не понимаю страницу - person Jozkee; 03.02.2017
comment
@ChildGG, просто вставьте свою фабрику в какой-нибудь data в объекте resolve, как UserService в примере. После этого просто верните ту же реализацию, которую вы присвоили переменной обещания в своем вопросе. - person Tome Pejoski; 03.02.2017
comment
@ChildGG рад помочь. Пожалуйста, проголосуйте и примите мой ответ, если он помог. Ваше здоровье! - person Tome Pejoski; 04.02.2017