Fragmented Thought

Lazy Loading Angular (<= 1.3) Controllers

By

Published

Lance Gliser

Heads up! This content is more than six months old. Take some time to verify everything still works as expected.

As your angular application grows, you'll quickly look for ways to distribute logic into manageable portions. You could (and should) simply produce js files dedicated to directives, controllers, and app separately, then use grunt to create your production file. But, you can do one better than that. You can simply not load entire sections of the site the user never visits. Through the use of require.js and angular's ui-router you can lazy load page controllers on demand, just like the template files.

File Breakdown

To make this work you'll need the following setup:

index.html

<head> ... </head> <body> <div id="wrap"> <!-- ... --> <main id="main" ng-include="Page.mainUrl"> <div ng-view autoscroll="true" class="slide"></div> </main> <!-- ... --> </div> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.min.js" ></script> <script type="text/javascript" src="/assets/require.min.js"></script> <script type="text/javascript" src="/app/core/app.js"></script> </body>

app.js

// declare app and modules var app = angular.module('main', [ 'ngRoute' // ... ]); // Prepare configuration to lazy load items based on route app.config([ '$routeProvider', '$controllerProvider', '$compileProvider', '$filterProvider', '$provide', // ... function( $routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide, // ... ) { ... // save references to the providers so we can lazy load items later app.lazy = { controller: $controllerProvider.register, directive: $compileProvider.directive, filter: $filterProvider.register, factory: $provide.factory, service: $provide.service, }; /* Routes */ $routeProvider // Standard routing .when('/', { templateUrl : 'app/core/templates/home.html', controller : 'mainCtrl' }) // Lazy loading routing .when('/maintenance', { templateUrl : 'app/maintenance/index.html', controller : 'maintenanceCtrl', resolve: { load: ['$q', '$rootScope', function ($q, $rootScope) { var deferred = $q.defer(); require ([ 'app/maintenance/controller', // (will look for controller.js) ], function () { $rootScope.$apply(function () { deferred.resolve(); }); }); return deferred.promise; }] } }); // ... }]);

Lazy controller setup

The new controllers are pretty much exactly the same as normal controllers. The only difference is the initial controller loading that looks like this:

app.lazy.controller("maintenanceCtrl", function ( $scope // ... ) { // ... });