最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ANGULAR-UI-ROUTER: Resolve state from URL - Stack Overflow

programmeradmin1浏览0评论

I'm making an app with dynamical states, and sometimes I need to resolve the state name from the url.

e.g.: I have /dashboard/user/12268 and I need to get the state 'dashboard.user'.

Is there any way to do this with the tools given by ui-router? I can't find out how to do this right now...

I'm making an app with dynamic module loading with 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. 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. I've started trying with urlMatcherFactory but can't resolve them.

The state is loaded after the URL resolution.

The flow is (after the refresh of page http://localhost:8090/index.html#/dashboard/user/12268):

  • bootstrap the app (without states)
  • at this point, ui-router has been loaded
  • 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.

My data-main in RequireJS has this initialization code:

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

I'm making an app with dynamical states, and sometimes I need to resolve the state name from the url.

e.g.: I have /dashboard/user/12268 and I need to get the state 'dashboard.user'.

Is there any way to do this with the tools given by ui-router? I can't find out how to do this right now...

I'm making an app with dynamic module loading with 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. 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. I've started trying with urlMatcherFactory but can't resolve them.

The state is loaded after the URL resolution.

The flow is (after the refresh of page http://localhost:8090/index.html#/dashboard/user/12268):

  • bootstrap the app (without states)
  • at this point, ui-router has been loaded
  • 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.

My data-main in RequireJS has this initialization code:

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

TheloadManifest function registers all after-bootstrap elements on my app (services, factories, controllers, routers, ...).

Thanks for your help,
Alx

Share Improve this question edited Apr 27, 2015 at 10:28 Alex Such asked Apr 27, 2015 at 9:49 Alex SuchAlex Such 4714 silver badges11 bronze badges 3
  • 2 Please post what you have so far – tim Commented Apr 27, 2015 at 9:53
  • I'm making an app with dynamic module loading with 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. 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. I've started trying with urlMatcherFactory but can't resolve them The state is loaded after the URL resolution – Alex Such Commented Apr 27, 2015 at 9:56
  • UI-Router Extras Future States can manage your scenario for you: christopherthielen.github.io/ui-router-extras/#/future – Chris T Commented Apr 28, 2015 at 13:21
Add a comment  | 

4 Answers 4

Reset to default 17

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

You can expose the internal state implementation by using the .decorator hook on $stateProvider. 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(), e.g.

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

Second, loop over each state in $state.get() and test them against your URL fragment.

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.

It results that the states stored in the service have more information that the one given on the $state.get() method. So I iterated over them to get a state that matches with my 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

To get @Chris T solution to work for me I am doing this inside a Service:

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:

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

The current state can be obtained from $state service. like $state.current Check this api http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state

发布评论

评论列表(0)

  1. 暂无评论