Monday, April 18, 2016

Dynamically Loading AngularJS Controllers using JQuery

Hi, My code is not new and most of the code is copied from

It acts as useful code snippet for myself and anyone who is looking for one.

I adapted the code to load the js files using JQuery instead of RequireJS, and it follows predefined naming convention for url, templates and js files:
  1. Url and file name: all small letters with each word separated with - (hyphen).
  2. Controller name: first letter of each word is caps with no gaps and ends with 'Ctrl'.
Save $controllerProvider as a property of angularjs app module and use RouteProvider object in $routeProvider config:
   var app = angular.module("app", ['ngRoute']);
        app.config(function ($routeProvider, $controllerProvider) {
            var route = new RouteProvider(); 
            .when('/view-one', route.resolve("view-one"))
            .when('/view2', route.resolve("view2"))
            .when('/view3', route.resolve("view3"))
                redirectTo: '/'

            app.register =
                controller: $controllerProvider.register

RouteProvider takes care of dynamically loading of js controller files using Jquery:
          var RouteProvider = function () {
            var scriptPath = "/Scripts/";
            var templatePath = "/Templates/";

            this.resolve = function (name) {
                var route = {};
                route.templateUrl = templatePath + name + ".html";
                route.controller = getControllerName(name) + "Ctrl";
                route.controllerAs = "vm";
                route.resolve = {
                    load: ['$q', '$rootScope', function ($q, $rootScope) { return loadController($q, $rootScope, scriptPath + name + ".js"); }]
                return route;
            var getControllerName = function (name) {
                var ctrlName = "";
                name.split("-").forEach(function (input) { ctrlName += input.substring(0, 1).toUpperCase() + input.substring(1).toLowerCase(); });
                return ctrlName;
            var loadController = function ($q, $rootScope, path) {
                var defer = $q.defer();
                    dataType: "script",
                    cache: true,
                    url: path
                }).done(function () { 
                return defer.promise;

Register the controller (view3.js) after load with $controllerProvider:
(function (app) {
    app.register.controller('View3Ctrl', ['$http', function ($http) {
        var vm = this;
        vm.value = "Hello from view3";
        vm.gotHttp = !!$http;
})(app || angular.module("app"));

view3.html template code:
<h3>view three</h3> 
<span ng-bind="vm.value"></span> <br /> 
<div>got $http - {{vm.gotHttp}}</div> 

Libraries used: jquery, angularjs v1.4 and angular-route