Monday, April 7, 2014

Angular and TypeScript Integration - Constructing an Angular Module from a TypeScript Module

In Angular there is such a thing as a 'module'. In TypeScript there is such thing as a 'module'. The two are basically different things. They are both kind of namespaces, but the two don't connect. It's a little confusing for people coming to a Angular/TypeScript project. Another thing that has bothered me and that I have written about is that if you define a controller or service in a TypeScript way you need some additional lines somewhere to include it into a module (the angular version).

The solution I have come up with is to construct an Angular module via dynamically inspecting TypeScript modules. This allows me to define my module like so:

angular.moduleFromNamespace("moduleName", My.NameSpace, []);

This creates a better Angular/TypeScript integration because angular modules are built from TypeScript modules. The way it works is that anything in My.NameSpace.Controllers is checked for injectability and if it is injectable it is injected as a controller. It determines "injectability" by looking for an injection property. Then the process happens for services, filters, and so on. I have briefly though about tightening this even more so that you could figure the namespace based on the module name. Here is the initial code:


angular.extend(angular, (function () {
    var config = [{
        fn: "controller",
        spaceName: "Controllers"
    }, {
        fn: "service",
        spaceName: "Services"
    }];
    var addTypeFromNamespace = function (module, inclusionFn, nameSpace) {
        Object.keys(nameSpace)
            .forEach(function (name) {
                var possibleTarget = nameSpace[name];
                if (possibleTarget && 'injection' in possibleTarget) {
                    inclusionFn.apply(module, [name, possibleTarget.injection]);
                }
            });
    };
    var fromNamespace = function (name, namespace, requires, configFn) {
        var module = angular.module(name, requires, configFn);
        config.forEach(function (option) {
            addTypeFromNamespace(
                module, 
                module[option.fn], 
                namespace[option.spaceName]);
        });
        return module;
    };
    return {
        moduleFromNamespace: fromNamespace
    };
})());

The variable names are bad and it could probably use a little more error handling. It is also ES5, but polyfills take care of that. It also needs to have the config section expanded.

If anyone wants me to put this on github they should mention it in the comments.

2 comments:

  1. Great efforts put it to find the list of articles. Thanks for your article.We are also one of the best sources to learn
    Angular JS Training in Chennai | Angular JS Training Institute in Chennai

    ReplyDelete
  2. Wonderful blog & good post. It is really very helpful to me, waiting for a more new post. Keep Blogging
    Angular JS Online training
    Angular JS training in Hyderabad

    ReplyDelete