66

The best I've found is http://www.ng-newsletter.com/posts/angular-ui-router.html. It doesn't go as deep as, for example, the order in which $stateChangeStart, exampleState.onEnter, exampleState.resolve, and exampleState.templateProvider fire.

A great answer format would be clean. Something like:

  1. Initial pageload of state foo:

    1. Angular lifecycle step 1
    2. UI router lifecycle step 1
    3. UI router lifecycle resolves occur
    4. UI router lifecycle onEnter fires
    5. Angular lifecycle step 2
  2. State change foo -> bar

    1. $stateChangeStart event fires
    2. foo onExit fires
    3. bar onEnter Fires
    4. templateUrl gets the template
    5. UI router plugs back into the Angular lifecycle in the digest loop (or wherever).
  3. Nested states

  4. Multiple named views:

  5. ui-sref clicked

Etc... Thanks!

EDIT: Debugging functions provided enough insight to meet the need. See my answer below for a snippet.

Community
  • 1
  • 1
Adam
  • 2,873
  • 3
  • 18
  • 17
  • did you look here: https://github.com/angular-ui/ui-router#resources – luksch Dec 23 '13 at 14:52
  • 1
    Thanks. Yes. Many times. The issue prompting this question was trying to use a resolved variable in templateProvider. According to the in-depth guide, templateProvider has access to locals. It fails silently if a resolve variable is used. Setting a breakpoint in templateProvider didn't work because the fail happened sometime before that. When was unclear. Not knowing the lifecycle, it was difficult to know what step happened prior to templateProvider in order to set a breakpoint there. So this question is to help me debug any other silent failure problems that come up. – Adam Dec 23 '13 at 15:12
  • I understand now better. I did not come across this yet. But then, my use of the ui-route thing is pretty simplistic. now i am interested too. +1 – luksch Dec 23 '13 at 16:34

5 Answers5

173

After some experimenting, I figured out how to see into the lifecycle well enough to debug my app and get a feel for what was happening. Using all the events, including onEnter, onExit, stateChangeSuccess, viewContentLoaded from here, gave me a decent picture of when things are happening in a way that's more both more flexible and specific to my code than a written out lifecycle. In the app module's "run" function, I placed:

This code would have saved me days of time and confusion if I started using it when I first started with Angular and UI-router. UI-router needs a "debug" mode that enables this by default.

$rootScope.$on('$stateChangeStart',function(event, toState, toParams, fromState, fromParams){
  console.log('$stateChangeStart to '+toState.name+'- fired when the transition begins. toState,toParams : \n',toState, toParams);
});
$rootScope.$on('$stateChangeError',function(event, toState, toParams, fromState, fromParams, error){
  console.log('$stateChangeError - fired when an error occurs during transition.');
  console.log(arguments);
});
$rootScope.$on('$stateChangeSuccess',function(event, toState, toParams, fromState, fromParams){
  console.log('$stateChangeSuccess to '+toState.name+'- fired once the state transition is complete.');
});
$rootScope.$on('$viewContentLoading',function(event, viewConfig){
   console.log('$viewContentLoading - view begins loading - dom not rendered',viewConfig);
});

/* $rootScope.$on('$viewContentLoaded',function(event){
     // runs on individual scopes, so putting it in "run" doesn't work.
     console.log('$viewContentLoaded - fired after dom rendered',event);
   }); */

$rootScope.$on('$stateNotFound',function(event, unfoundState, fromState, fromParams){
  console.log('$stateNotFound '+unfoundState.to+'  - fired when a state cannot be found by its name.');
  console.log(unfoundState, fromState, fromParams);
});
Oliver Salzburg
  • 21,652
  • 20
  • 93
  • 138
Adam
  • 2,873
  • 3
  • 18
  • 17
  • 9
    This is what @Adam means by app module's run function: `angular.module('MyModule').run(['$rootScope',function($rootScope){ // put the event handlers here }]);` – Endy Tjahjono Sep 28 '14 at 14:30
29

I took @Adam's solution and wrap it into a service so I can switch debugging (printing to console) on and off from within my application.

In the template:

<button ng-click="debugger.toggle()">{{debugger.active}}</button>

In the controller:

function($scope, PrintToConsole){ $scope.debugger = PrintToConsole; }

Or to just switch it on:

angular.module('MyModule', ['ConsoleLogger'])
.run(['PrintToConsole', function(PrintToConsole) {
    PrintToConsole.active = true;
}]);

The service:

angular.module("ConsoleLogger", [])
.factory("PrintToConsole", ["$rootScope", function ($rootScope) {
    var handler = { active: false };
    handler.toggle = function () { handler.active = !handler.active; };
    $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
        if (handler.active) {
            console.log("$stateChangeStart --- event, toState, toParams, fromState, fromParams");
            console.log(arguments);
        };
    });
    $rootScope.$on('$stateChangeError', function (event, toState, toParams, fromState, fromParams, error) {
        if (handler.active) {
            console.log("$stateChangeError --- event, toState, toParams, fromState, fromParams, error");
            console.log(arguments);
        };
    });
    $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
        if (handler.active) {
            console.log("$stateChangeSuccess --- event, toState, toParams, fromState, fromParams");
            console.log(arguments);
        };
    });
    $rootScope.$on('$viewContentLoading', function (event, viewConfig) {
        if (handler.active) {
            console.log("$viewContentLoading --- event, viewConfig");
            console.log(arguments);
        };
    });
    $rootScope.$on('$viewContentLoaded', function (event) {
        if (handler.active) {
            console.log("$viewContentLoaded --- event");
            console.log(arguments);
        };
    });
    $rootScope.$on('$stateNotFound', function (event, unfoundState, fromState, fromParams) {
        if (handler.active) {
            console.log("$stateNotFound --- event, unfoundState, fromState, fromParams");
            console.log(arguments);
        };
    });
    return handler;
}]);
Endy Tjahjono
  • 24,120
  • 23
  • 83
  • 123
  • 3
    I think it's also better to inject $log and then we can simplify the service even further to lines like that: $log.debug("$viewContentLoading --- event, viewConfig", arguments); – Ilya Chernomordik Jan 14 '16 at 11:36
2

How ui-router manages urls beside the default $location provider is not clear so, adding more debugging code here. Hopefully it'll be helpful. These are from https://github.com/ryangasparini-wf/angular-website-routes

$scope.$on('$routeChangeError', function(current, previous, rejection) {
    console.log("routeChangeError", currrent, previous, rejection);
});

$scope.$on('$routeChangeStart', function(next, current) {
    console.log("routeChangeStart");
    console.dir(next);
    console.dir(current);
});

$scope.$on('$routeChangeSuccess', function(current, previous) {
    console.log("routeChangeSuccess");
    console.dir(current);
    console.dir(previous);
});

$scope.$on('$routeUpdate', function(rootScope) {
    console.log("routeUpdate", rootScope);
});
s6712
  • 496
  • 5
  • 14
2

I needed to debug the ui-router I was using along with the ui-router-extras sticky state package. I found that sticky states has builtin debugging that helped solve my problem. It logs information about the state transitions and which are inactive/active.

https://christopherthielen.github.io/ui-router-extras/#/sticky

angular.module('<module-name>').config(function ($stickyStateProvider) {
    $stickyStateProvider.enableDebug(true);
});
Zack Huston
  • 426
  • 5
  • 6
1

UI Router has been updated with Transition Hooks.

Use $transition$ service to access onError hook and catch the error.

List of hook :

  • onBefore - The transition is about to start
  • onStart - The transition has started
  • onExit - (state events) Any exiting states are exited
  • onRetain - (state events) Any retained states are retained
  • onEnter - (state events) Any entering states are entered
  • onFinish - The transition is about to finish
  • onSuccess - he transition is finished and is either successful or errored.
  • onError - he transition is finished and is either successful or errored.

You can checkout the overview to learn about Transition : https://ui-router.github.io/guide/transitions

See the documentation for the Transition Hook events : https://ui-router.github.io/guide/transitionhooks

Disfigure
  • 720
  • 6
  • 19