Заставить AngularJS ui-router / app ждать данные $ http для предотвращения FOUC

0

У меня есть следующий вопрос... или ситуация. У меня есть определения, определенные в моем приложении AngularJS, например...

$stateProvider
            .state('myApp', {
                abstract: true,
                template: '<ui-view/>'
            })
            .state('myApp.stateOne', {
                url: 'state1',
                templateUrl: '/an/views/state-1.html',
                controller: 'StateOneCtrl'
            })
            .state('myApp.stateTwo', {
                url: 'state2',
                templateUrl: '/an/views/state-2.html'
                controller: 'StateTwoCtrl'
            })
            .state('myApp.stateThree', {
                url: 'state3',
                templateUrl: '/an/views/state-3.html'
                controller: 'StateThreeCtrl'
            })

Есть больше состояний, и я изменил название для этого примера, но предположим, что мне нужно проверить, разрешено ли пользователю видеть/загружать 'mayApp.stateThree'. Я могу определить это, обратившись к бэкэнду. У меня есть служба (в этом примере называется IsAllowedService) для обработки этих запросов/предоставления доступа, и обычно я бы написал логику для проверки в .run() в файле app.js, например:

.run(['IsAllowedService', '$state', function (IsAllowedService, $state) {

        $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) {

            // check if we are going to sfm.addContacts and if we are allowed to...
            if (toState.name === 'myApp.stateThree') {
                IsAllowedService.checkIfIsAllowed().then(function (resp) {
                    if(resp.allowed === false) {
                        $state.go('myApp.stateOne');
                    }
                });
            }

        });

}]);

Это работает хорошо, но не дожидаясь, пока мы получим результат от службы, поэтому загрузится "mayApp.stateThree", после чего мы перенаправляем, если необходимо. Таким образом, мы получаем быструю вспышку страницы, прежде чем перенаправляемся. Я мог бы поместить тот же код в 'StateThreeCtrl' но я все равно получаю flash/FOUC. Можно ли разрешить это при определении состояний, я знаю, что это не сработает, но что-то вроде этого...

.state('myApp.stateThree', {
    url: '/an/state3',
    templateUrl: '/an/views/state-3.html'
    controller: 'StateThreeCtrl',
    resolve: {
        isAllowed : function () {
        IsAllowedService.checkIfIsAllowed().then(function (resp) {
            return resp;
            })
        }
    }

Я понимаю, что я не смог бы внедрить услугу (или даже службу $http), но возможно ли мне как-то приостановить загрузку представления/контроллера " mayApp.stateThree ", пока я не получу результат от IsAllowedService.checkIfIsAllowed(). Любые советы о том, как структурировать мое приложение/код, будут оценены. Я использовал ng-cloak в своем HTML-представлении, но это ничего не делало!

Теги:

1 ответ

0

Фактически вы делаете это почти правильно в блоке запуска приложения. Кроме того, что вы ничего не мешаете. Это можно сделать, добавив:

  event.preventDefault(); //Prevent from going to the page

Кроме того, вы можете добавить пользовательские данные в свои $ states, что позволит вам проверить эти условия с вашими критериями. например:

$stateProvider.state('home', {
  controller: 'HomeController as home',   
  url: '/home',
  templateUrl: 'home.html',
  data: { roles: [ROLES.ANONYMOUS] }}); //This can be any condition 
$stateProvider.state('user', {
  controller: 'UserController as user', 
  url: '/user',
  templateUrl: 'user.html', 
  data: { roles: [ROLES.ADMIN, ROLES.USER] }});

Вы можете получить эти пользовательские данные в событии $ stateChangeStart:

  $rootScope.$on('$stateChangeStart', function (event, next) {
    if (!yourService.isAuthorized(next.data.roles)) { 
      event.preventDefault(); //Prevent from going to the page -> no flickering
      $state.go('403'); //Or whatever is desired.
    } 
  });

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

       if (toState.name === 'myApp.stateThree') {
            event.preventDefault(); //preventing the request.
            IsAllowedService.checkIfIsAllowed().then(function (resp) {
                if(resp.allowed === false) {
                    $state.go('myApp.stateOne');
                } else { //he actually is allowed to go to state three.
                   $state.go('myApp.stateThree');
                } 
            }, function() { //in case the server has no answer
              $state.go('myApp.stateOne'); //you probably want to prevent it too
        } );

На мой взгляд, если эти условия не изменяются во время выполнения, то есть на основе роли пользователя, вы можете получить их при проверке пользователя, чтобы вам не потребовалось обещание начать. Надеюсь это поможет.

Я сделал подобное сообщение раньше и добавил working плункер.

  • 0
    Привет, если вы посмотрите на примеры, которые я привел второй пример кода является блоком .run ()
  • 0
    Я скоро обновлю его, извините, я прошел слишком быстро.
Показать ещё 2 комментария

Ещё вопросы

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