Monday, April 18, 2016

Dynamically Loading AngularJS Controllers using JQuery


Hi, My code is not new and most of the code is copied from http://weblogs.asp.net/dwahlin/dynamically-loading-controllers-and-views-with-angularjs-and-requirejs

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(); 
            $routeProvider
            .when('/view-one', route.resolve("view-one"))
            .when('/view2', route.resolve("view2"))
            .when('/view3', route.resolve("view3"))
            .otherwise({
                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();
                $.ajax({
                    dataType: "script",
                    cache: true,
                    url: path
                }).done(function () { 
                        $rootScope.$apply();
                        defer.resolve();
                });
                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:
   
<div> 
<h3>view three</h3> 
<span ng-bind="vm.value"></span> <br /> 
<div>got $http - {{vm.gotHttp}}</div> 
</div>



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