Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular ui.router infinite loop on $state or $location change

I am at the end of my wits, nerves, everything, for the past 4 hours I am TRYING to debug and reading all over the internet what the problem might be with this.

So, I am working on mocking up a mobile application and my logic is like this:

  1. If the user has logged in the past, we have data in localStorage about that, then show him the listing. this is offline
  2. If we are connected to the internet, show the listing first and in the background check to see if he is still logged in
  3. If HE ISN'T, redirect to login page.

On the main Home view, I am evaluating the above statements, first I show him the listing if he has localStorage data, then I check online and redirect to login if necessary.

Whenever I have two $state or $locations it loops. Like the browser almost freezes, lucky it's Chrome. and I get the Cannot call method 'insertBefore' of null. From what I read, a known angular.ui router issue, if used bad or some other mystical problem.

Some Code:

These event emitters and receivers, which I call in the return of my StateManagement Services

//Notification Helpers, also exposed, to keep them in the same scope tree.
        function emitNotification (event, data) {
            console.log('Emitting event: ' + event);
            $rootScope.$emit(event, data);

        }

        function emitListen (event, fn) {
            console.log('Listening for: ' + event);
            $rootScope.$on(event, function (e, data) {
                fn(data);
            });

        }

. . .LOGIC

//Update the userData in localStorage and in .value
                                $auth.storage.set('userData', data);
                                userData = $auth.storage.get('userData'); //TODO: Redundant, store it directly, is it ok?

                                emitNotification('event:auth-okServer', data);
                                //return 'ok-server';

... return my service

},
            loginSuccess: function(data){
                emitNotification('event:auth-loginSuccess', data);
            },
            loginFailed: function(data){
                emitNotification('event:auth-loginFailed', data);
            },
            notify: emitNotification,
            listen: emitListen

And this is in my controller:

.config(function config($stateProvider) {
        $stateProvider
            .state('sidemenu.home', {
                url: '/home',
                views: {
                    'topView': {
                        controller: 'HomeCtrl',
                        templateUrl: 'home/home.tpl.html'
                    }
                }
            })
            .state('sidemenu.home.list', {
                url: '/list',
                templateUrl: 'home/home-list.tpl.html',
                controller: 'ListCtrl'
            })
            .state('sidemenu.home.login', {
                url: '/login',
                templateUrl: 'home/home-login.tpl.html',
                controller: 'LoginCtrl'
            })
            .state('sidemenu.home.register', {
                url: '/register',
                templateUrl: 'home/home-register.tpl.html',
                controller: 'RegisterCtrl'
            })
            .state('sidemenu.home.coach', {
                url: '/coach',
                templateUrl: 'home/home-coach.tpl.html',
                controller: 'CoachCtrl'
            })
            ;
    })

    .controller('HomeCtrl', function HomeController($scope, $state, $location, localState) {

        /**
         * EVENT EMITTERS
         * @event:auth-loginSuccess - Login has been succesfull, let everybody know.
         * @event:auth-loginFailed  - Login has failed, do something.
         * @event:auth-okServer     - Server challenge ok, user is logged in.
         * @event:auth-okLocal      - Local challenge ok, user appears to be logged in.
         * @event:auth-login        - Go to login
         * @event:general-coach     - Start the coach
         **/


        /**
         * ===== FIRST LOGIC =====
         **/


        //We are placing emitters in the same children-parent tree scope, the one from localState, and we're listening to them.
        localState.listen('event:auth-okLocal', function(data) {
            console.log('EVENT: auth-okLocal has been triggered');
            //$state.transitionTo('sidemenu.home.list');
            $location.path('/sidemenu/home/list');
            //First we will be redirected on listpage
        });

        localState.listen('event:auth-login', function() {
            console.log('EVENT: auth-login has been triggered');
            $location.path('/sidemenu/home/login');
        });
        //Server check fails, redirect to login
        localState.listen('event:general-coach', function(data) {
            console.log('EVENT: general-coach has been triggered');
            //$state.transitionTo('sidemenu.home.coach');
            $location.path('/sidemenu/home//coach');
        });

        //After we have all the listeners in place do the checking & broadcasting.
        localState.check();

What am I doing wrong?

I have debugged the emitters, my check() function which creates all the emitters, I have tried several combinations on ui.router and I have miserably failed :).

like image 767
Arthur Kovacs Avatar asked Apr 05 '14 22:04

Arthur Kovacs


1 Answers

I had the same problem with the same use-case, it is a bug with ui router, but waiting for it to finish the state change before transitioning solved it:

if (webAPIAuth.isLoggedIn()) { $scope.$on('$stateChangeSuccess', function () { $state.go('dashboard'); }); }

like image 126
Kenneth Lynne Avatar answered Oct 22 '22 06:10

Kenneth Lynne