12
votes

I'm about to rip my brains out trying to define an Angular module in TypeScript while using RequireJS. Have looked all over for a solution while spending days trying to figure it all out to no avail. Please help, I'm so confused!

I'm not using Visual Studio, but rather WebStorm. This shouldn't really matter however. I'm using TS 9.1, AngularJS 1.0.7, RequireJS 2.1.8. I've also tried using DefinitelyTyped's angular.d.td, but it's not helping.

Does anyone have a simple example of a TS angular app module for app init, with another TS angular module that has a controller, being loaded with RequireJS, referencing "DefinitelyTyped/angularjs/angular.d.ts", and calling 'angular.module' to define themselves, and then referencing the controller in a web page?

Please, help.... I'm burning in TypeScript, RequireJS, AngularJS module hell.

2
Personally I don't see any benefit for using requirejs anymore for the internals of your app. Will be doing a video tutorial on my current workflow soon. But if you know grunt you can look at : github.com/basarat/video-angular-typescript which uses npmjs.org/package/grunt-tsbasarat
I don't use Angular, but I use Dojo (which has its own version of RequireJS) with TypeScript. Took a couple of tries to figure out. Some of the details are a bit tricky, especially since TypeScript defaults to CommonJS-style modules which are incompatible with RequireJS. You can look into my github.com/schungx/Dojo-TypeScript for some inspiration. I have a sort of manual which details how to use TypeScript with Dojo, and you should get some ideas from there.Stephen Chung

2 Answers

22
votes

I was able to use these 3 technologies together. I added angular.d.ts and other files from DefinitelyTyped to my Visual Studio project but I also needed to add module declarations using declare module statements. That's because angular definitions from DefinitelyTyped are written for usage without AMD/requirejs. Maybe it is better to use jquery and angular without AMD (load it using <script> tag) and use AMD only for application modules but anyway here is example extracted from my project:

index.html

<script src="webjars/requirejs/2.1.11/require.js" data-main="js/requireMain"></script>

requireMain.ts

Main file for requirejs. It is TypeScript file but doesn't use import syntax and rather uses usual requirejs syntax. It also declares angular modules.

require.config({
    baseUrl: '../js',
    paths: {
        'jquery': '../webjars/jquery/1.11.0/jquery',
        'angular': '../webjars/angularjs/1.2.16/angular',
        'angular-route': '../webjars/angularjs/1.2.16/angular-route',
        'angular-resource': '../webjars/angularjs/1.2.16/angular-resource',
        'angular-ui-bootstrap': '../webjars/angular-ui-bootstrap/0.10.0/ui-bootstrap-tpls',
    },
    shim: {
        'jquery': { exports: 'jquery' },
        'angular': { exports: 'angular', dep: ['jquery'] },
        'angular-route': { exports: 'angular-route', deps: ['angular'] },
        'angular-resource': { exports: 'angular-resource', deps: ['angular'] },
        'angular-ui-bootstrap': { exports: 'angular-ui-bootstrap', deps: ['angular'] },
    },
});

// TypeScript declarations useful for importing angular modules
declare module 'angular' {
    var angular: ng.IAngularStatic;
    export = angular;
}
declare module 'angular-route' {
}
declare module 'angular-resource' {
}
declare module 'angular-ui-bootstrap' {
}

require(['jquery', 'angular', 'angular-route', 'angular-resource', 'angular-ui-bootstrap', 'bootstrap', 
    'application', 'routes'],
    function ($: JQueryStatic, angular: ng.IAngularStatic, angularRoute, angularResource, angularUiBootstrap,
        application, routes) {
        $(function () {
            angular.bootstrap(document, ['application']);
        });
    });

application.ts

import angular = require('angular');
import angularRoute = require('angular-route');
import angularResource = require('angular-resource');
import angularUiBootstrap = require('angular-ui-bootstrap');

var application = angular.module('application', ['ngRoute', 'ngResource', 'ui.bootstrap']);
export = application

routes.ts

import application = require('application');
import myModule = require('myModule');

application.config(function ($routeProvider) {
    $routeProvider.
        when('/myPage', { controller: myModule.MyPageCtrl, templateUrl: 'partials/myPage.html' }).
        otherwise({ redirectTo: '/myPage' });
});

myModule.ts

import application = require('application');
import angularUiBootstrap = require('angular-ui-bootstrap');
import myService = require('myService');

export interface MyPageCtrlScope {
    someData: string;
    someAction: () => void;
}

export class MyPageCtrl {

    constructor(public $scope: MyPageCtrlScope, private PersonService: myService.PersonResourceClass, private $modal: ng.ui.bootstrap.IModalService) {

        PersonService.additionalAction({}).$promise.then(
            (person) => {
                this.$scope.someData = person.email;
            });

        $scope.someAction = this.someAction.bind(this);
    }

    someAction() {
        this.$modal.open({
            templateUrl: 'dialog.html'
        }).result.then(
            () => {
                this.$scope.someData = 'something else';
            });
    }

}

myService.ts

import application = require('application');
import angularResource = require('angular-resource');

export interface Person {
    id?: number;
    email?: string;
}

export interface PersonResource extends Person, ng.resource.IResource<PersonResource> {
}

export interface PersonResourceClass extends ng.resource.IResourceClass<PersonResource> {
    additionalAction(person: Person): PersonResource;
}

application.factory('PersonService', function ($resource: ng.resource.IResourceService, apiUrl: string): PersonResourceClass {
    return <PersonResourceClass> $resource(apiUrl + '/person/:id', { id: "@id" }, {
        'additionalAction': { method: 'POST', url: apiUrl + '/person/:id/additionalAction' },
    });
});
3
votes

There are no stoppers in this scenario that I am aware of, we are using in a large app internally. Publicly I have this small sample : https://github.com/basarat/TypeScriptDeepDive that uses all three.

To help you debug I am sure there is some non TS issue you are having with RequireJS + Angular. The simplest way to narrow it down is to define the following variables:

declare var angular:any;
declare var define:any; 
declare var require:any; 

This will allow you to use straight up TypeScript as though it was javascript, at least for requirejs/angularjs.

Then you can sort out your issues and pull in the type definitions for angular / requirejs.