Friday, April 4, 2014

Angular and TypeScript - Patterns for Controllers

Note: I feel I have solved the issues below and talked about it in another post.

-----------------------------------------------------

When combining Angular and TypeScript one of the basic questions is: how do you create a controller? A common Angular way is to define the controller function like so:

angular.module('my.module.name', [])
    .controller('controllerName', function(...) {...});

In TypeScript you typically want to attach type information into a controller and people from the typed world of classes want to make something like a Controller into a class, because in the Java/C#/C++ world all things are organized into classes. Okay, so one solution is to put your controller into a class like so:

module MyNameSpace.Controllers {
    export class MyController {
        public static injection = ['injectable',MyController];
        constructor(injectable: typeOfInjectable) {
            ...
        }
    }
}

Now you have separated the defining of the controller object from its inclusion in a module. So you will need an additional line like:

angular.module('my.module.name', [])
    .controller('controllerName', MyController.injection);

Where do you put this line? You can either put it in the file with the controller or in some file that constructs the module. For our project we currently do the later.

So the drawbacks of putting it in the controller file itself is that you have to wait for the controller class to exist before you can add it to a module. This means how have to add a line at the bottom. Now this can be boilerplate with the module name and controller name being variables of the controller class. That way it could just be included in a template and the two variables could be near the top of the class.

The drawbacks of the way we do it now are that every time you want to add a controller you have to touch two files. This doesn't seem like a big deal, but I feel like adding a controller should be easy and it is easy to forget to add it into the module which ends up wasting time.

Another way is to search a namespace and automatically include controllers from a registered namespace into your module. This ends up being a little magical, but you just need to have some namespace discipline and everything works fine.

To recap, if you define your controller as a class here are three ways to include it into the module.

Explicitly in another file

File - Controller
module MyNameSpace.Controllers {
    export class MyController {
        public static injection = ['injectable',MyController];
        constructor(injectable: typeOfInjectable) {
            ...
        }
    }
}

File - Module
angular.module('my.module.name', [])
    .controller('controllerName', 
                MyNameSpace.MyController.injection);


Controller defines what Module it belongs to

File - Module
angular.module("my.module.name", []);

function addController(controller: IController) {
    angular.module(controller.moduleName)
        .controller(controller.controllerTag,
                    controller.injection);
}

File - Controller
module MyNameSpace.Controllers {
    export class MyController: IController {
        public static moduleName = "my.module.name";
        public static controllerTag = "controllerName";
        public static injection = ['injectable',MyController];
        constructor(injectable: typeOfInjectable) {
            ...
        }
    }

    addController(MyController);
}

Module Searches a NameSpace

File - Module
function addControllersFromNamespace(module, namespace) {
    Object.keys(namespace).forEach((controllerName) => {
        var possibleController = namespace[controllerName];
        if (possibleController &&
            'injection' in possibleController) {
            module.controller(
                controllerName,
                possibleController.injection)
        }
    });
}
var module = angular.module("my.module.name");
addControllersFromNamespace(module, MyNameSpace.Controllers);

This code is a little rough, but it is intended to express patterns and not necessarily be ready to put into your code. For example, I have put in global functions which you shouldn't do.

As to which is superior, I am not sure. I certainly think touching only one file is easier of course their is a small amount of complexity to alleviate this, but I think it is probably worth it.

1 comment:

  1. Thanks for your detailed explanation about MVC model in Angualr.There is big demand for Angular Developers in all over the world.You can take this oppurtunities to improve your stable career option.
    Angular JS Training in Chennai | Angular JS Training Institute in Chennai

    ReplyDelete