ANGULAR-UI-ROUTER:从URL解析状态

时间:2015-04-27 09:49:28

标签: javascript angularjs angular-ui angular-ui-router

我正在创建一个具有动态状态的应用,有时我需要从网址中解析状态名称。

例如:我有/dashboard/user/12268,我需要获得状态'dashboard.user'

有没有办法用ui-router给出的工具做到这一点?我现在无法知道如何做到这一点......

我正在使用requireJS加载动态模块。第一次没有问题,因为用户被发送到登录状态。登录后,我使用require只加载用户有权访问的状态。但是当用户重新加载页面时,我再次加载模块,并需要将URL解析为状态,并且存在问题。我已经开始尝试使用urlMatcherFactory但无法解决它们。

在URL解析后加载状态。

流程是(在刷新页面http://localhost:8090/index.html#/dashboard/user/12268之后):

  • 引导应用程序(无状态)
  • 此时已加载ui-router
  • 获取用户有权访问的状态并注册它们(这些状态在配置阶段后注册)
  • 找出我是否有一个匹配给定网址的状态重定向到那里。这就是我被困住的地方。

要在应用程序引导程序之后加载状态,我使用了包含状态和常量的Ben Nadel's solution变体。

RequireJS中的data-main有这个初始化代码:

require.config({
    // REQUIREJS CONFIGURATION
});

require(['app'], function (app) {
    app.bootstrap(document);

    var ng = angular.injector(['ng']);
    var $window = ng.get('$window')
    var $q = ng.get('$q');

    var appStorage = $window.localStorage;
    var loadedManifests;

    try {
        loadedManifests = JSON.parse(appStorage.getItem('loadedManifests'));
    } catch(e) {
        loadedManifests = [];
    }

    if (!angular.isArray(loadedManifests) || loadedManifests.length === 0) {
        $q.all([
                app.loadManifest('login/manifest'), //loadMainfest function loads the states for login
                app.loadManifest('logout/manifest') //load states for logout
            ])
            .then(function () {
                app.injector.get('$rootScope').$evalAsync(function () {
                    app.injector.get('$state').go('login');
                });
            });
    } else {
        var promisesArray = [];

        for(var i = 0; loadedManifests[i]; i++) {
            promisesArray.push(app.loadManifest(loadedManifests[i])); //load all manifests registered on localstorage
        }

        $q.all(promisesArray).then(function(){
            //TODO: Stuck. Get URL from querystring and resolve to valid state, or redirect to /login
        });
    }
});

loadManifest函数在我的应用程序(服务,工厂,控制器,路由器......)上注册所有后引导元素。

感谢您的帮助,
ALX

4 个答案:

答案 0 :(得分:17)

https://github.com/angular-ui/ui-router/issues/1651

您可以使用.decorator上的$stateProvider挂钩公开内部状态实现。你可以装饰国家建设者的任何财产;我随意选择了“父母”。

app.config(function($stateProvider) { 
  $stateProvider.decorator('parent', function (internalStateObj, parentFn) {
     // This fn is called by StateBuilder each time a state is registered

     // The first arg is the internal state. Capture it and add an accessor to public state object.
     internalStateObj.self.$$state = function() { return internalStateObj; };

     // pass through to default .parent() function
     return parentFn(internalStateObj); 
  });
});

现在,您可以使用.$$state()访问内部状态对象,例如

var publicState = $state.get("foo");
var privateInternalState = publicState.$$state();

其次,遍历$ state.get()中的每个状态,并根据您的URL片段对它们进行测试。

angular.forEach($state.get(), function(state) { 
  var privatePortion = state.$$state();
  var match = privatePortion.url.exec(url, queryParams);
  if (match) console.log("Matched state: " + state.name + " and parameters: " + match);
});

答案 1 :(得分:1)

最后,我必须对ui-router的$state服务进行一些小修改才能找到解决方案。

结果是存储在服务中的状态具有的信息比$state.get()方法中给出的信息多。所以我迭代它们以获得与我的URL匹配的状态:



/**
 * @ngdoc function
 * @name ui.router.state.$state#fromUrl
 * @methodOf ui.router.state.$state
 * 
 * @description
 * A method to resolve a state and its parameters from a given URL
 *
 * @returns {boolean} Returns a state that matches with the given URL, or undefined if no match
 */
$state.fromUrl = function(url) {
  if(!angular.isString(url)) {
    //Only valid strings allowed
    return undefined;
  }
  
  
  var keys = objectKeys(states);
  //Iterate over all states
  for(var i = 0; i < keys.length; i++) {
    var state = states[keys[i]];
    var stateArgs = state.url.exec(url);

    //If the state's URL does not match then stateArgs will be false
    if(!!stateArgs) {
      return {
        name: state.name,
        args: stateArgs
      }
    }
  }

  return undefined;
};
&#13;
&#13;
&#13;

的问候,
ALX

答案 2 :(得分:0)

要让@Chris T解决方案为我工作,我在服务中执行此操作:

app.service('Helper', ['$state', '$location',
    function($state, $location){

       var services = {};

       services.stateIs = function(state_name){
          var current_path = $location.$$path;
          var state = $state.get(state_name);

          if(state){
              var state_regexp = state.$$state().url.regexp;
              return state_regexp.test(current_path);
          }else{
              return false;
          }
       }

       return services;
    }
]);

所以稍后我可以在任何地方注入Helper并执行此操作:

if(Helper.stateIs('app.user')){
    //yeah 
}

答案 3 :(得分:-2)

当前状态可以从$ state service获得。像$state.current 检查此api http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state