Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why $state.go doesn't work when destination state or it's parent resolves with promise

I tried to load some data on parent state with resolve and to redirect user to default state when the app runs like so:

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

  $stateProvider.state('home', {
    url: '/',
    template: '<div><a ui-sref="home">Start App</a> <a ui-sref="home.main">Home</a> <a ui-sref="home.other">Other state</a><div ui-view>Loading...</div></div>',
    resolve: {
      user: ['$timeout', '$q', 
        function($timeout, $q) {
          var deferred = $q.defer();
          var promise = deferred.promise;
          var resolvedVal = promise.then(function() {
            console.log('$timeout executed');
            return {Id: 12, email: '[email protected]', name: 'some name'};
          }, function() {
            console.log('Error happend');
          });
          $timeout(function() {
            deferred.resolve();
          }, 2000);
          return resolvedVal;
        }]
      //user: function() {return {id: 222, name: 'testname', email: '[email protected]'}; }
    },
    controller: ['$scope', 'user', function($scope, user) {
      $scope.user = user;
    }]
  });

  $stateProvider.state('home.other', {
    url: 'other',
    template: '<div>Your name is {{user.name}}, and email is {{user.email}}</div><div>This is other state of application, I try to make it open as default when application starts, by calling to $state.transitionTo() function in app.run() method</div>',
    resolve: {
      someObj: function() {
        console.log('hello');
        return {someProp: 'someValue'};
      }  
    },
    controller: ['$scope', 'user', function($scope, user) {
      $scope.user = user;
    }]    
  });

}]);  

app.run(['$state', '$rootScope', function ($state, $rootScope) {
  $state.go('home.other');   
}]);

And this does not change url in address bar and does not show template of home.other state (though the resolve function of home.state is executed and there is 'hello' in console). But when I comment promise function in resolve and instead put there simple function returning object application redirects as expected.

Also instead of $timeout tried to do $http request which will actually be there, but no luck too.

like image 751
user3357257 Avatar asked Feb 26 '14 18:02

user3357257


1 Answers

And to answer my own question - unwanted behavior happend because of digest cycle starts to handle requested url after $state.go('home.other') was called and as the resolve function creates deffered object, though this object is resolved, state engine already passes to the requested url's state. So to prevent this I used the technic explained below:

If you need to discard execution of requested url's state resolvation in certain curcumstances when the application startes, you can use $stateChangeStart event, like this:

app.run(['$state', '$rootScope', '$timeout', function ($state, $rootScope, $timeout) {
  var appStarted = 0; // flag to redirect only once when app is started
  $rootScope.$on('$stateChangeStart', 
  function(event, toState, toParams, fromState, fromParams) { 
    if(appStarted) return;
    appStarted = 1;   
    event.preventDefault(); //prevents from resolving requested url
    $state.go('home.other'); //redirects to 'home.other' state url
  });  
}]);
like image 83
user3357257 Avatar answered Sep 28 '22 07:09

user3357257