简体   繁体   English

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

[英]ANGULAR-UI-ROUTER: Resolve state from URL

I'm making an app with dynamical states, and sometimes I need to resolve the state name from the url. 我正在创建一个具有动态状态的应用程序,有时我需要从URL解析状态名称。

eg: I have /dashboard/user/12268 and I need to get the state 'dashboard.user' . 例如:我有/dashboard/user/12268 ,我需要获得状态'dashboard.user'

Is there any way to do this with the tools given by ui-router ? ui-router提供的工具有没有办法做到这一点? I can't find out how to do this right now... 我现在无法知道如何做到这一点......

I'm making an app with dynamic module loading with requireJS. 我正在使用requireJS进行动态模块加载的应用程序。 At first time there is no problem because user is sent to login state. 第一次没有问题,因为用户被发送到登录状态。 After login, I use require to load only the states the user has access to. 登录后,我使用require只加载用户有权访问的状态。 But when the user reloads the page, I load the modules again, and need to resolve the url to a state, and there's the problem. 但是当用户重新加载页面时,我再次加载模块,并需要将URL解析为状态,并且存在问题。 I've started trying with urlMatcherFactory but can't resolve them. 我已经开始尝试使用urlMatcherFactory但无法解决它们。

The state is loaded after the URL resolution. 在URL解析后加载状态。

The flow is (after the refresh of page http://localhost:8090/index.html#/dashboard/user/12268 ): 该流程是(在刷新页面http://localhost:8090/index.html#/dashboard/user/12268 ):

  • bootstrap the app (without states) 引导应用程序(没有状态)
  • at this point, ui-router has been loaded 此时, ui-router已经加载
  • get the states the user has access to, and register them (these states are registered after config phase) 获取用户有权访问的状态,并注册它们(这些状态配置阶段注册)
  • find out if i have a state that matches the given url to redirect to there. 找出我是否有一个匹配给定网址的状态重定向到那里。 This is where I'm stuck. 这就是我被困住的地方。

To load states after application bootstrap, I've used a variation of Ben Nadel's solution that includes states and constants. 为了在应用程序引导之后加载状态,我使用了Ben Nadel解决方案的变体,其中包括状态和常量。

My data-main in RequireJS has this initialization code: 我在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 }); } }); 

The loadManifest function registers all after-bootstrap elements on my app (services, factories, controllers, routers, ...). loadManifest函数在我的应用程序(服务,工厂,控制器,路由器......)上注册所有后引导元素。

Thanks for your help, 谢谢你的帮助,
Alx ALX

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

You can expose the internal state implementation by using the .decorator hook on $stateProvider . 您可以使用$stateProvider上的.decorator挂钩公开内部状态实现。 You can decorate any property of the state builder; 你可以装饰国家建设者的任何财产; I chose 'parent' arbitrarily. 我随意选择了“父母”。


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); 
  });
});

Now you can access the internal state object using .$$state() , eg 现在,您可以使用.$$state()访问内部状态对象,例如

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

Second, loop over each state in $state.get() and test them against your URL fragment. 其次,遍历$ 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);
});

Finally I've had to make a small modification on ui-router's $state service to get to the solution. 最后,我不得不对ui-router的$state服务进行一些小修改才能找到解决方案。

It results that the states stored in the service have more information that the one given on the $state.get() method. 结果是存储在服务中的状态具有更多的信息,这些信息是在$state.get()方法中给出的。 So I iterated over them to get a state that matches with my URL: 所以我迭代它们以获得与我的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; }; 

Regards, 问候,
Alx ALX

To get @Chris T solution to work for me I am doing this inside a Service: 要让@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;
    }
]);

So later I can inject Helper anywhere and do this: 所以后来我可以在任何地方注入Helper并执行此操作:

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

The current state can be obtained from $state service. 当前状态可以从$ state service获得。 like $state.current Check this api http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state $state.current检查这个api http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM