2016-07-19 2 views
0

Я не уверен, что это дубликат или нет, но мне не удалось найти что-то, что сработало для меня, поэтому я отправляю этот вопрос.Угловое изменение состояния после обещания

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

Если я переведу e.preventDefault() прямо перед $state.go(..), тогда это работает, но не правильно. Проблема в том, что он начинает загружать состояние по умолчанию и когда получает ответ от http, только затем перенаправляет его на main.home. Итак, скажем, если запрос db занимает примерно 2 секунды, то требуется 2 секунды, прежде чем перенаправить на main.home, что означает, что пользователь видит контент, на который он не должен находиться примерно на 2 секунды.

Есть ли способ предотвратить дефолт в начале изменения состояния и перенаправить пользователя в конце изменения состояния? Кроме того, если мы можем предотвратить дефолт в начале изменения состояния, то как мы можем продолжить состояние по умолчанию?

(function(){ 
    "use strict"; 
    angular.module('app.routes').run(['$rootScope', '$state', '$http', function($rootScope, $state, $http){ 
     /* State change start */ 
     $rootScope.$on('$stateChangeStart', function(e, to, toParams, from, fromParams){ 
      e.preventDefault(); 
      $http 
       .get('/url') 
       .error(function(err){ 
        console.log(err); 
       }) 
       .then(function(response){ 
        if(response.data === 2){ 
         // e.preventDefault() 
         $state.go('main.home'); 
        } 
        // direct to default state 
       }) 
     } 
    }]); 
}); 

ответ

1

Вы можете добавить resolve секцию в $ stateProviderConfig.

Внутри разрешения вы можете отправить запрос на базу данных и проверить необходимые условия. Если вы не хотите, чтобы пользователь присоединился к этой странице, вы можете использовать $ state.go(), чтобы перенаправить его в другое место.

Пример конфигурации:

.state({ 
    name: 'main.home', 
    template: 'index.html', 
    resolve: { 
     accessGranted: ['$http', '$state', '$q', 
      function($http, $state, $q) { 
       let deffered = $q.defer(); 
       $http({ 
        method: 'GET', 
        url: '/url' 
       }).then(function(data) { 
        if (data === 2) { 
         // ok to pass the user 
         deffered.resolve(true); 
        } else { 
         //no access, redirect 
         $state.go('main.unauthorized'); 
        } 
       }, function(data) { 
        console.log(data); 
        //connection error, redirect 
        $state.go('main.unauthorized'); 
       }); 
       return deffered.promise; 
      } 
     ] 
    } 
}); 

Документация resolve доступна here

Обратите внимание, что вы могли бы использовать Promise объект вместо $ д службы в случае, если вам не нужно поддерживать IE

+0

Спасибо, он прекрасно работает. (Я думаю, вы должны ввести $ q также в свой пример) – Timo

0

Одним из способов справиться с этой ситуацией является добавление перехватчика следующим образом.

.config(function ($httpProvider) { 
     $httpProvider.interceptors.push('stateChangeInterceptor'); 
    }).factory('stateChangeInterceptor', function ($q, $window,$rootScope) { 
     return { 
      'response': function(response) { 
       var isValid = true;//Write your logic here to validate the user/action. 
       /* 
       * Here you need to allow all the template urls and ajax urls which doesn't 
       */ 
       if(isValid){ 
        return response; 
       } 
       else{ 
        $rootScope.$broadcast("notValid",{statusCode : 'INVALID'}); 
       } 

      }, 
      'responseError': function(rejection) { 
       return $q.reject(rejection); 
      } 
     } 
    }) 

Затем обработать сообщение 'notValid' следующим

.run(function($state,$rootScope){ 
     $rootScope.$on("notValid",function(event,message){ 
     $state.transitionTo('whereever'); 
    }); 
}) 
Смежные вопросы