«UI-Router-Extras» — невозможно прикрепить/добавить новые объекты «FutureState» после того, как App.Config() уже загружен

У меня возникают проблемы с добавлением новых состояний на этапе выполнения моего приложения с помощью «UI-Router-Extras».

Я уже довольно давно пытаюсь подключить и загрузить новые состояния ПОСЛЕ того, как пользователь успешно прошел аутентификацию с помощью плагина 'UI-Router-Extras' 'ui-router-extras'

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

ПРИМЕР КОДА В PLUNKER — НАЖМИТЕ КНОПКУ ВХОД -> http://plnkr.co/edit/PQwNQcLNMyPfpke076yy


Код ниже загружается и работает:


Мне удалось лениво загрузить исходный файл app.config() из внешнего файла. Как код описан ниже:


PUBLIC — внешние изначально загруженные маршруты с использованием "UI-Router-Extras" — "lazyload/states/public-states.json"

[
    {
        "name": "unauth",
        "url": "/",
        "controller": "LoginCtrl",
        "templateUrl": "app/components/core/login/login.html",
        "roles": ["public"]
    },
    {
        "name": "otherwise",
        "url": "/",
        "roles": ["public"]
    }
]

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

'use strict';

var app = angular.module('app', ['ui.router', 'ct.ui.router.extras'])

  .config(function ($urlRouterProvider, $stateProvider, $futureStateProvider) {

        app.stateProvider = $stateProvider; // MIGHT NEED REFERNCE LATER?
        app.futurestateProvider = $futureStateProvider;  // MIGHT NEED REFERNCE LATER?

        // ASYNC LOAD OF ROUTES AVAILABLE - SOON TO BE BY ROLE
        var futureStateResolve = ["$http", function($http) {
            return $http.get("lazyload/states/public-states.json").then(function(response) {
                angular.forEach(response.data, function(state) {

                    $stateProvider.state(state);
                    console.log(state.roles);

                })
            })
        }];

        $futureStateProvider.addResolve(futureStateResolve);
        console.log($futureStateProvider);

  });



Код ниже НЕ работает


Ниже мой код для той части, которая не работает:

PRIVATE – внешние изначально загруженные маршруты с использованием "UI-Router-Extras" – "lazyload/states/public-states.json"

Этот json ниже предназначен для добавления после входа пользователя в систему с использованием отложенной загрузки и FutureStates. Пока не повезло :(

[
    {
        "name": "app",
        "abstract": true,
        "url": "?menu1State",
        "templateUrl": "app/components/core/layout/layout.html",
        "controller": "LayoutCtrl",
        "roles": ["level1"]
    },
    {
        "name": "app.dashboard",
        "url": "/app",
        "views": {
            "feature": {
                "templateUrl": "app/components/core/features/features.html",
                "controller": "FeatureCtrl"
            }
        },
        "roles": ["level1"]
    },
    {
        "name": "app.associations_beanbags",
        "url": "/app/associations/bean-bags?myParam1&myParam2&modalState",
        "views": {
            "feature": {
                "templateUrl": "app/components/core/features/associations/bean-bags.html",
                "controller": "BeanbagsCtrl"
            }
        },
        "roles": ["level2"]
    }
]

Кнопка входа в систему, запускающая ленивое создание состояний после успешной аутентификации:

<a id="btn-fblogin" href="" class="btn btn-primary pull-right" ng-click="callNotify(username, password);">Login</a>


Что происходит, когда пользователь нажимает кнопку входа в систему, он имитирует успех и вызывает «$scope.callNotify», запуская код, который вы видите ниже. В итоге все работает до тех пор, пока не появится 'app.futurestateProvider.futureState(newState);' и попытка вызвать новое состояние, чтобы узнать, было ли добавлено '$state.go( 'app.dashboard');'. Все это приводит к ошибке, которая гласит следующее:

Ошибка консоли:

Error: Could not resolve 'app.dashboard' from state 'unauth'
at Object.transitionTo (http://localhost:3000/bower_components/angular-ui-router/release/angular-ui-router.js:2521:17)
at Object.$state.transitionTo (http://localhost:3000/bower_components/ui-router-extras/release/ct-ui-router-extras.js:136:34)
at Object.$state.transitionTo (http://localhost:3000/bower_components/ui-router-extras/release/ct-ui-router-extras.js:874:55)
at Object.$state.transitionTo (http://localhost:3000/bower_components/ui-router-extras/release/ct-ui-router-extras.js:1301:48)
at Object.go (http://localhost:3000/bower_components/angular-ui-router/release/angular-ui-router.js:2454:21)
at http://localhost:3000/app/components/core/auth/auth-service.js:58:13
at http://localhost:3000/bower_components/angular/angular.js:8113:11
at wrappedCallback (http://localhost:3000/bower_components/angular/angular.js:11573:81)
at wrappedCallback (http://localhost:3000/bower_components/angular/angular.js:11573:81)
at http://localhost:3000/bower_components/angular/angular.js:11659:26 

Для меня это похоже на то, что состояния никогда не добавлялись, когда мы ожидали, что приводит к ошибке, говорящей что-то вроде «Извините, я не вижу маршрут, который вы ищете».

'use strict';

app.controller('AuthServiceTestCtrl', ['$window','$scope','$http', '$state', function (win, $scope, $http, $state) {

    $scope.callNotify = function(username,password, $stateProvider, $futureStateProvider) {
            //notify(username, password); // CALL SERVICE AND GET A RETURN VALUE / ACTION

            var loadedAgain = $http.get("lazyload/states/private-states.json").success(function(response) {

                if(username == "[email protected]" && password == "abc123"){

                    console.log('Valid Credentials. Logging In.');

                    // NOW THAT USER IS LOGGED IN REGISTER NEW PRIVATE ROUTE / STATES - PREFERABLY FROM THE SECURED SERVER FILE ('private-states.json') ABOVE
                    var adminModuleFutureStates = [
                        {
                            "name": "app",
                            "abstract": true,
                            "url": "?menu1State",
                            "templateUrl": "app/components/core/layout/layout.html",
                            "controller": "LayoutCtrl",
                            "roles": ["level1"]
                        },
                        {
                            "name": "app.dashboard",
                            "url": "/app",
                            "views": {
                                "feature": {
                                    "templateUrl": "app/components/core/features/features.html",
                                    "controller": "FeatureCtrl"
                                }
                            },
                            "roles": ["level1"]
                        },
                        {
                            "name": "app.associations_bean-bags",
                            "url": "/app/associations/bean-bags?myParam1&myParam2&modalState",
                            "views": {
                                "feature": {
                                    "templateUrl": "app/components/core/features/associations/bean-bags.html",
                                    "controller": "BeanBagsCtrl"
                                }
                            },
                            "roles": ["level2"]
                        }
                    ];

                    angular.forEach(adminModuleFutureStates, function(newState) {
                        console.log(newState);
                        app.futurestateProvider.futureState(newState); // WAS SAVED AS A VAR IN APP CONFIG FOR LATER REFERENCE
                    });

                    // FINALLY GO TO ONE OF THE NEWLY ADDED PRIVATE STATES WE JUST ADDED WHICH IS A DASHBOARD
                    $state.go('app.dashboard');

                }
            });

        };
    }]);

Мне очень жаль, что у меня нет готового рабочего примера, я сейчас на нем, но я решил опубликовать это сейчас, чтобы показать, что у меня есть, и, возможно, получить обсуждение или решение о том, как я могу загружать состояния к ui-router во время выполнения через мой контроллер, указанный выше, после того, как приложение уже загрузило конфигурацию и т. д.

В конечном итоге я пытаюсь сделать следующее:

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

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

Серьезно! Большое спасибо!

ПРИМЕР КОДА В PLUNKER — НАЖМИТЕ КНОПКУ ВХОД -> http://plnkr.co/edit/PQwNQcLNMyPfpke076yy


person Frankie Loscavio    schedule 21.10.2014    source источник
comment
@Framkie, вы нашли решение этой проблемы?   -  person Asik    schedule 25.02.2015


Ответы (1)


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

angular.module("app").configInjector.invoke(['$stateProvider', function ($stateProvider) {

Затем, после настройки инжектора приложений, аутентификации пользователя и проверки роли (ролей) сервером, ответ json, определяющий разрешенные представления/маршруты/состояния ui-router, зацикливается и динамически добавляется в определения состояний ui-router. . Эти маршруты определены в json, как и любые сопутствующие контроллеры и представления, которые загружаются отложенно с помощью $ocLazyLoad.

В целом я сделал следующее:

angular.module("auth")
.factory('AuthRouteLoaderFactory', ['$window', '$rootScope', '$http', '$state', '$cookieStore','$location', '$timeout','AuthSession',
    function(win, $rootScope, $http, $state, $cookieStore, $location, $timeout, AuthSession) {

        // PRIVATE INTERFACE
        function loadPrivateRoutes() {

            console.log('AuthRouteLoaderFactory :: LOADING PRIVATE ROUTES');

            var loadedPrivateRoutes = $http.get("lazyload/states/private-states.json").success(function (response) {

        angular.module("app").configInjector.invoke(['$stateProvider', function ($stateProvider) {

                    // VERY IMPORTANT - POST LOGIN ROUTE LOADER / INJECTOR;// DYNAMIC AND SERVER DETERMINED JSON ITERATED BASED ON SPECIFIC ROLES PRE-MADE BY SERVER.
                    angular.forEach(response, function (state) {

                        if(!state.abstract){
                            state.views.feature.resolve[state.views.feature.data.controllerAlias] = ['$ocLazyLoad', function($ocLazyLoad){return $ocLazyLoad.load({"name": state.views.feature.data.controllerAlias,"files": state.views.feature.data.controllerFiles})}];
                            state.views.feature.resolve.isAuthenticated = function(){
                // CHECK IF WE ARE A VALID SESSION FOR EACH LAZY LOAD
                //AuthSession.validateToken();
              };
                        }

                        console.log('AuthRouteLoaderFactory :: loadPrivateroutes state loaded -> ' + state.name);
                        $stateProvider.state(state.name, state);
                    });

                    $state.go('app.dashboard');

                }]);

            });

        }

        // FOR NOW WE LOAD ROUTES ANYWAY UNTIL WE CALL API'S /ME OR PING SERVICE, THEN ON SUCCESS WE LOAD ROUTES
        if(AuthSession.validateToken()){
          $rootScope.hideLoader = true;
          loadPrivateRoutes();
          console.log('AuthRouteLoaderFactory :: SESSION VALIDATION SUCCESSFUL :: PROCEED');
        }

        // PUBLIC INTERFACE
        return {
            testFactory: function() {
                console.log('AuthRouteLoaderFactory :: testFactory');
            },
            isSessionValid: function(){
                return $cookieStore.get('fakeLoginSession');
            },
            invalidateSession: function(){
                $cookieStore.remove('fakeLoginSession');
                $location.path('/login.html');
            },
            loadRoutes: loadPrivateRoutes
        };
    }
]);

Общедоступные состояния/маршруты:

[
    {
        "name": "unauth",
        "url": "/",
        "controller": "LoginCtrl",
        "templateUrl": "app/components/core/login/unauth.html",
        "data": {
            "roles": ["public"]
        }
    },
    {
        "name": "login",
        "url": "/login",
        "controller": "LoginCtrl",
        "templateUrl": "app/components/core/login/unauth.html",
        "data": {
            "roles": ["public"]
        }
    },
    {
        "name": "otherwise",
        "url": "/",
        "data": {
            "roles": ["public"]
        }
    }
]

Частные государства/маршруты:

[
    { "name": "app", "abstract": true, "url": "", "templateUrl": "app/components/core/layout/layout.html", "controller": "LayoutCtrl" },
    {
        "name": "app.dashboard",
        "views": {
            "feature": {
                "templateUrl": "lazyload/components/core/features/dashboard/dashboard.html",
                "controller": "DashboardCtrl as dashboard",
                "resolve": {},
                "data": {
                    "controllerAlias": "dashboard",
                    "controllerFiles": ["lazyload/components/core/features/dashboard/dashboard-controller.js"]
                }
            }
        }
    },
    {
        "name": "app.associations_role-type",
        "views": {
            "feature": {
                "templateUrl": "lazyload/components/core/features/associations/role-type.html",
                "controller": "RoleTypeCtrl as roleType",
                "resolve": {},
                "data": {
                    "controllerAlias": "roleType",
                    "controllerFiles": ["lazyload/components/core/features/associations/role-type-controller.js"]
                }
            }
        }
    }
]
person Frankie Loscavio    schedule 26.03.2015