Search code examples
angularjsroutesngrouteangularjs-ng-include

Angular ngRoute not working on reload with ngInclude


In case anyone else runs into the same issue. While trivial to some, it was not trivial for me.

The problem:

When the page loads ngRoute fails to load the shell (landing page) template when using ng-view inside ng-include.

However if we start navigating around the pages including navigating back to landing page then the template loads just fine. It is as if the first time the page loads it completely skips loading the landing template.

The setup:

Somewhere at the bottom of index.html's body:

<script src="angular-route.js"></script>

Somewhere in index.html template

<div ng-include="'root-shell.html'"></div>

Somewhere in root-shell.html template

<div ng-view></div>

The JS:

(function (/* IIFE enclosed code*/) {

    angular('myApp', [$routeProvider]);

    angular('myApp').config(function($routeProvider){

        $routeProvider
            .when('/', {
                templateUrl: 'root-shell.html',
                controller: 'RootShellController', // optional
                controllerAs: 'rootShellCtrl' // optional
            }).
            .when('/about', {
                templateUrl: 'about.html',
                controller: 'AboutController', // optional
                controllerAs: 'aboutCtrl' // optional
            }).
            otherwise({
                redirectTo: '/'
            });
    });

})(/* IIFE invoke*/);

Solution

  • Why the problem?

    Because if ng-view instantiation is delayed (through ng-include) then the $route instantiation is delayed as well. This means that $route will miss the location change event.

    The fix:

    Force a reload of the $route service.

    angular('myApp').run(['$route', function($route)  {
        $route.reload();
    }]);
    

    Why does it work?

    Because of angular's order of execution:

    1. app config
    2. app run
    3. directive setup
    4. directive compile
    5. app controller
    6. directive link
    7. ** Data resolve called **
    8. new route's controller

    and the run block:

    Run blocks are the closest thing in Angular to the main method. A run block is the code which needs to run to kickstart the application. It is executed after all of the services have been configured and the injector has been created. Run blocks typically contain code which is hard to unit-test, and for this reason should be declared in isolated modules, so that they can be ignored in the unit-tests.

    Disclaimer:

    I am fairly new to Angular, therefore if I've misunderstood and/or misrepresented a concept then by all means chime in.