Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angularjs infdig error when change state on ui-router(with video)

New Edit: the authservice that checks the login:

'use strict';

angular.module('MainApp.login.services', [])
    .factory('authService', ['AUTH_ENDPOINT', 'LOGOUT_ENDPOINT', '$http', '$cookieStore', function (AUTH_ENDPOINT, LOGOUT_ENDPOINT, $http, $cookieStore) {
        var auth = {};
        auth.login = function (username, password) {
            return $http.post(AUTH_ENDPOINT, {username: username, password: password})
                .then(function (response, status) {
                    auth.user = response.data;
                    $cookieStore.put('user', auth.user);
                    return auth.user;
                });
        };
        auth.logout = function () {
            return $http.post(LOGOUT_ENDPOINT).then(function (response) {
                auth.user = undefined;
                $cookieStore.remove('user');
                $cookieStore.remove('event');
            });
        };
        return auth;
    }])
    .value('AUTH_ENDPOINT', 'http://www.mydomain.gr/assets/modules/login/dal/login.php')
    .value('LOGOUT_ENDPOINT', 'http://www.mydomain.gr/assets/modules/login/dal/logout.php');  

Updated:
Unfortunatelly this is a part of a whole web-application , so i cant upload it on jsfiddle. I made a youtube video where i show exactly the error while i debug the application. From minute 1:30 starts the problem.Feel free to examine the video
below is the app.js of my angular application.

Could the $watch(es) that i have into the templates ,create the error?

Youtube, after 1:30 starts the error : https://www.youtube.com/watch?v=3Cc2--BkdQ4&feature=youtu.be

When first load the site , the login screen loads and asks for the credentials.

If the user login it redirects to the part4 page(from inside the login controller) , so far so good!

The problem is whenever i open a new tab on the browser , try to load the website:

  1. It should see that the user is already loged in and redirect him on the part4 page.

  2. instead of this , as i see on the debug of the browser , it goes to the resolve:login

  3. Then it goes up inside $rootScope.$on('$stateChangeError', and to the go.state(part4)

  4. Then it goes to the resolve of part4 and then it goes to the resolve of the login and again to the $statechangeerror function

5.And finally i get the error :Error: [$rootScope:infdig] http://errors.angularjs.org/1.4.8/$rootScope/infdig?p0=10&p1=%5B%5D but the strange is that it finally redirects to the part4 page, but with that error!!

Can anyone help me please.

'use strict';

var app = angular.module('MainApp', ['mApp',
    'MainApp.loginModule',
    'MainApp.part4Module',
    'MainApp.part5Module',
    'MainApp.eventModule',
    'ui.router', 'ui.router.tabs', 'ngCookies']);

angular.module('MainApp')
    .run(['$rootScope', '$state', '$cookieStore', 'authService', function ($rootScope, $state, $cookieStore, authService) {
        $rootScope.$on('$stateChangeError', function (event, toState, toParams, fromState, fromParams, error) {
            if (error.unAuthorized) {
                $state.go('login');
            }
            else if (error.authorized) {
                $state.go('part4');
            }
        });

        authService.user = $cookieStore.get('user');
    }])
    .config(function ($stateProvider, $urlRouterProvider, $locationProvider) { //$stateProvider & $urlRouterProvider are from ui.router module
        $stateProvider
            .state('floorplan', {
                url: '/floorplan/:activeEventId/:activeHallId/:activeHallVariant',
                controller: 'ParticipantsCtrl',
                templateUrl: '/assets/modules/part1/part1.html',
                resolve: {
                    user: ['authService', '$q', function (authService, $q) {
                        return authService.user || $q.reject({unAuthorized: true});
                    }]
                }
            })
            .state('event', {
                url: '/event/:activeEventId',
                templateUrl: 'assets/modules/event/eventPartial.html',
                controller: 'eventctrl',
                resolve: {
                    user: ['authService', '$q', function (authService, $q) {
                        return authService.user || $q.reject({unAuthorized: true});
                    }]
                }
            })
            .state('part4', {
                url: '/part4',
                resolve: {
                    user: ['authService', '$q', function (authService, $q) {
                        return authService.user || $q.reject({unAuthorized: true});
                    }]
                },
                controller: 'part4ctrl',
                templateUrl: '/assets/modules/part4/part4Partial.html'
            })
            .state('login', {
                url: '/login',
                controller: 'LoginCtrl',
                templateUrl: '/assets/modules/login/login.html',
                resolve: {
                    user: ['authService', '$q', function (authService, $q) {
                        if (authService.user) {   
                         return $q.reject({authorized: true});
                        }
                    }]
                }
            });
        $urlRouterProvider.otherwise('login');
    });

enter image description here

I uploaded a video on youtube , describing and showing the error: youtube: https://www.youtube.com/watch?v=3Cc2--BkdQ4&feature=youtu.be

like image 301
Theo Itzaris Avatar asked Feb 25 '16 21:02

Theo Itzaris


3 Answers

I think the state is resolved first because you inject $state in your app.run.

Which lead to try to resolve the part4 state's resolve with undefined user, then the event is thrown and will be resolved on the next digest cycle, so the use is initialized before you get redirecit to login page, which will redirect you to part4.

Try to separate in two angular.run, the 1st that will run the init of the authService without injectingt $state. The 2nd that will inject the $state to init the$stateCHangeError listener (just defining the 1st one before the 2nd one).

If it's not enough : split your module : the one containing the authService in a module 'A' with the dedicated angular.module('A').run, the 2nd in a module 'B' with a dependency toward 'A' with the angular.module('B').run for the $stateChangeError

like image 60
Walfrat Avatar answered Nov 03 '22 01:11

Walfrat


Can you try this inverted?

.run(['$rootScope', '$state', '$cookieStore', 'authService', function ($rootScope, $state, $cookieStore, authService) {
    $rootScope.$on('$stateChangeStart', function (...) {
    authService.user = $cookieStore.get('user');
                if (authService.user) {
                    $state.go('part4');
                }
                else if (!authService.user) {
                    $state.go('login');
                }
            });
}

This will skip the to and fro to the $q within your resolve in each route's declaration. Second, this will also resolve you/r checking user all the time within resolve of each route. In .config() set authService.user = $cookieStore.get('user'); somewhere. Should resolve your issue.

like image 40
Gary Avatar answered Nov 02 '22 23:11

Gary


Everything seems ok.

After many hours and many breakpoints i realized that the problem was not caused by any $watch(), i have many $watch on my controllers.

It is just a state problem, as you can see on my question , i didnt have '/' state, and that caused the infinite loop ,because:

  1. when i delete the extension part of the url , i have : www.mydomain.com/ , then the $stateProvider searches my available 'states' but couldnt find '/' state, so it redirects to 'login' state.
  2. Into 'login' state i check if user==true and reject error.
  3. Then , $rootScope.$on('$stateChangeError'){..} executes and i call state.go('part4') , it resolves state 'part4' and again it goes to state 'login' resolve ,and again the same until the maximum number of allowed iterations of the $digest cycle reached.

How i solved it

I dont know if it is the best way but i added a '/' state on app.js, and it works as expected:

.state('/', {
                url: '/',
                controller: 'LoginCtrl',
                templateUrl: '/assets/modules/login/login.html',
                resolve: {
                    user: ['authService', '$q', function (authService, $q) {
                        if (authService.user) {
                            return $q.reject({authorized: true, user: authService.user});
                        }
                    }]
                }
            });
like image 43
Theo Itzaris Avatar answered Nov 02 '22 23:11

Theo Itzaris