Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Am using the following template to configure a AngularJS/Typescript web app and receiving the following error.

The following error is appearing when I run the application:
0x800a139e - JavaScript runtime error: [$injector:modulerr] Failed to instantiate module app due to:

Error: [$injector:nomod] Module 'app' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.

I have checked this thread and ensured that I do indeed have a reference to angular-route.js

app.ts - Easier version to view + index.html

  /// <reference path="./typings/angularjs/angular.d.ts" />
'use strict';

// Create and register modules
var modules = ['app.controllers','app.directives', 'app.filters', 'app.services'];
modules.forEach((module) => angular.module(module, []));
angular.module('app', modules);

// Url routing
angular.module('app').config(['$routeProvider',
    function routes($routeProvider: ng.IRouteProvider) {
        $routeProvider
            .when('/', {
                templateUrl: 'views/MyView.html',
                controller: 'app.controllers.MyController'
            })
            .otherwise({
                redirectTo: '/'
            });
    }
]);

module app {
    export module controllers {}
    export module directives {}
    export module filters {}
    export module services {}

    export interface IController {}
    export interface IDirective {
        restrict: string;
        link($scope: ng.IScope, element: JQuery, attrs: ng.IAttributes): any;
    }
    export interface IFilter {
        filter (input: any, ...args: any[]): any;
    }
    export interface IService {}

    /**
     * Register new controller.
     *
     * @param className
     * @param services
     */
    export function registerController (className: string, services = []) {
        var controller = 'app.controllers.' + className;
        services.push(app.controllers[className]);
        angular.module('app.controllers').controller(controller, services);
    }

    /**
     * Register new filter.
     *
     * @param className
     * @param services
     */
    export function registerFilter (className: string, services = []) {
        var filter = className.toLowerCase();
        services.push(() => (new app.filters[className]()).filter);
        angular.module('app.filters').filter(filter, services);
    }

    /**
     * Register new directive.
     *
     * @param className
     * @param services
     */
    export function registerDirective (className: string, services = []) {
        var directive = className[0].toLowerCase() + className.slice(1);
        services.push(() => new app.directives[className]());
        angular.module('app.directives').directive(directive, services);
    }

    /**
     * Register new service.
     *
     * @param className
     * @param services
     */
    export function registerService (className: string, services = []) {
        var service = className[0].toLowerCase() + className.slice(1);
        services.push(() => new app.services[className]());
        angular.module('app.services').factory(service, services);
    }
}

Am a bit of a TS/Angular newbie so any help would be greatly appreciated.

Thanks

Potential Duplicate: AngularJS + TypeScript: cannot inject $routeProvider

share|improve this question
    
Which version of Typescript are you using? The template is pretty old and is throwing errors with both 0.9.1.1 and 0.9.5 branch. –  musically_ut Feb 15 at 12:42
    
I believe i am on 0.9.21 –  freschx Feb 16 at 0:39

2 Answers 2

up vote 2 down vote accepted
+50

You need to make a few changes to that template to get it to work.

Full source here

First ensure you have the correct references. Including a reference to angular-route.d.ts

/// <reference path="./typings/angularjs/angular.d.ts" />
/// <reference path="./typings/angularjs/angular-route.d.ts" />

'use strict';

// Create and register modules
var modules = ['app.controllers','app.directives', 'app.filters', 'app.services'];
modules.forEach((module) => angular.module(module, []));

To use the $routeProvider you must have included the ngRoute module in your modules, but because we don't want to register it with angular, because it already exists there, we need to push the module afterwards like this:

// *** Push ngRoute or $routeProvider won't work ***
modules.push("ngRoute");

angular.module('app', modules);

Then you need to fix the type of $routeProvider from ng.IRouteProvider to ng.route.IRouteProvider as that definition is wrong.

// Url routing
angular.module('app').config(['$routeProvider',
    function routes($routeProvider: ng.route.IRouteProvider) { // *** $routeProvider is typed with ng.route.IRouteProvider ***
        $routeProvider
            .when('/', {
                templateUrl: 'views/MyView.html',
                controller: 'app.controllers.MyController'
            })
            .otherwise({
                redirectTo: '/'
            });
    }
]);

Next TypeScript won't accept empty modules. So having export module controllers {} etc is pointless, because TSC won't include them, and they will be undefined giving errors. Unless you were to define at least one controller, directive, filter and service in your app. But this is solved by simply including null;

module app {
    export module controllers { null; }
    export module directives { null; }
    export module filters { null; }
    export module services { null; }

    export interface IController {}
    export interface IDirective {
        restrict: string;
        link($scope: ng.IScope, element: JQuery, attrs: ng.IAttributes): any;
    }
    export interface IFilter {
        filter (input: any, ...args: any[]): any;
    }
    export interface IService {}

    /**
     * Register new controller.
     *
     * @param className
     * @param services
     */
    export function registerController (className: string, services = []) {
        var controller = 'app.controllers.' + className;
        services.push(app.controllers[className]);
        angular.module('app.controllers').controller(controller, services);
    }

    /**
     * Register new filter.
     *
     * @param className
     * @param services
     */
    export function registerFilter (className: string, services = []) {
        var filter = className.toLowerCase();
        services.push(() => (new app.filters[className]()).filter);
        angular.module('app.filters').filter(filter, services);
    }

    /**
     * Register new directive.
     *
     * @param className
     * @param services
     */
    export function registerDirective (className: string, services = []) {
        var directive = className[0].toLowerCase() + className.slice(1);
        services.push(() => new app.directives[className]());
        angular.module('app.directives').directive(directive, services);
    }

    /**
     * Register new service.
     *
     * @param className
     * @param services
     */
    export function registerService (className: string, services = []) {
        var service = className[0].toLowerCase() + className.slice(1);
        services.push(() => new app.services[className]());
        angular.module('app.services').factory(service, services);
    }
}

That should now work and you can register your controllers, filters, services and directives. Such as:

module app.controllers
{
    export class testCtrl implements IController
    {
        constructor()
        {
            console.log("Test Controller");
        }
    }
}

app.registerController('testCtrl');

When referencing a controller, or service to use the full name. i.e:

<div ng-controller="app.controllers.testCtrl"></div>

Remember in your html to reference angular-route.js after angular.js. i.e:

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular-route.js"></script>
share|improve this answer
    
Very helpful, thanks Scott –  freschx Feb 17 at 21:32
    
@freschx You're welcome. Glad it helped. –  Scott Feb 17 at 21:41
    
Scott your answer managed to solve my main issue so again a big thanks, however I'm now getting a secondary error saying it cannot load the module ngLocale. (oi62.tinypic.com/ojkon.jpg) Where (and how) does one go about loading this module in app.ts? I've checked the doco here: docs.angularjs.org/error/$injector/nomod but can't quite get my head around it. –  freschx Feb 18 at 10:30
    
@freschx You can add further modules to your template by using modules.push("moduleName"); after the current modules.push("ngRoute"); line. So in this case modules.push("ngLocale");. Hope that helps :) –  Scott Feb 19 at 17:11

I found my sollution here a link!

"This didn’t help much but luckily I’d seen this before and recalled that it happens when I tried to include a module dependency that did not exist. This happens due to a number of reasons such as removing a script for index.html for a module but leaving in the module dependency or even misspelling a module dependency. (Turns out my issue was the former.) So this was easy to fix once you knew that."

share|improve this answer
    
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. –  LittleBobbyTables Jun 17 at 11:44

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.