3

I'm trying to add states dynamicaly to my app following the answer of that question : AngularJS - UI-router - How to configure dynamic views

app.run(['$q', '$rootScope', '$state', '$http',
  function ($q, $rootScope, $state, $http) 
  {
    $http.get("myJson.json")
    .success(function(data)
    {
      angular.forEach(data, function (value, key) 
      { 
          var state = {
            "url": value.url,
            "parent" : value.parent,
            "abstract": value.abstract,
            "views": {}
          };

          // here we configure the views
          angular.forEach(value.views, function (view) 
          {
            state.views[view.name] = {
              templateUrl : view.templateUrl,
            };
          });

          $stateProviderRef.state(value.name, state);
      });
      $state.go("home");    
    });
}]);

However i'm stuck like the guy in one of the last comment of the accepted answer, the states are created but i need to redirect users to the right state instead of just simply redirect them to home and i cannot get the $state.current.

For now i'm parsing all the available states and try to find a match with the current url, and if a match is found i redirect them to it. I saw a guy i don't remember where, doing it like this.

It works fine except for abstract states. Here is the code :

  var matchedState = null,
    matchedStateParams = null;

  angular.forEach($state.get(), function(state) {
    var url = state.url ? $urlMatcherFactory.compile(state.url) : null;
    var params = url ? url.exec($location.path(), $location.search()) : null;
    if (!matchedState && params && !state.abstract) {
      matchedState = state;
      matchedStateParams = params;
    }
  });

  if(matchedState != null) {
    $state.transitionTo(matchedState, matchedStateParams, {reload: true});
  }

Do you know a better way to achieve this and which works even with abstract states ?

Thanks a lot for your answers !

Community
  • 1
  • 1
Nomaki
  • 41
  • 1
  • 4

1 Answers1

5

The answer is also shown in this Q & A - our helpers will be two methods:

  • provider - $urlRouterProvider.deferIntercept();
  • service - $urlRouter.listen();

As described in doc (see cited parts below) we can use power of UI-Router to "stop url evaluation" in config phase and "re-run it again" at run phase, once all the states are dynamically defined...

This will be the part in the .config() phase

.config(['$stateProvider', '$urlRouterProvider',
  function($stateProvider, $urlRouterProvider) {

      $stateProviderRef = $stateProvider; 
       
      // here we will define default
      // and instract UI-Router to wait and wait and wait
      $urlRouterProvider.otherwise('/home');
      $urlRouterProvider.deferIntercept();

This is the .run() phase

.run(['$rootScope', '$urlRouter',
  function($rootScope, $urlRouter) {    

    $stateProviderRef
      .state('home', {
        url: "/home",
        templateUrl: 'tpl.html',
      })

    // now we will stop the waiting
    // the url evaluation will start again, and even dynamic stuff
    // will be properly triggered
    $urlRouter.listen();
  }
]);

Check this workig plunker

Documentation for this solution is here

$urlRouterProvider

The deferIntercept(defer)

Disables (or enables) deferring location change interception.

If you wish to customize the behavior of syncing the URL (for example, if you wish to defer a transition but maintain the current URL), call this method at configuration time. Then, at run time, call $urlRouter.listen() after you have configured your own $locationChangeSuccess event handler.

Cited snippet:

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

app.config(function($urlRouterProvider) {

  // Prevent $urlRouter from automatically intercepting URL changes;
  // this allows you to configure custom behavior in between
  // location changes and route synchronization:
  $urlRouterProvider.deferIntercept();

}).run(function($rootScope, $urlRouter, UserService) {

  $rootScope.$on('$locationChangeSuccess', function(e) {
    // UserService is an example service for managing user state
    if (UserService.isLoggedIn()) return;

    // Prevent $urlRouter's default handler from firing
    e.preventDefault();

    UserService.handleLogin().then(function() {
      // Once the user has logged in, sync the current URL
      // to the router:
      $urlRouter.sync();
    });
  });

  // Configures $urlRouter's listener *after* your custom listener
  $urlRouter.listen();
});
Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335