Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I define an AngularJS service using a TypeScript class that doesn't pollute the global scope?

I am using AngularJS and TypeScript. I want to implement an AngularJS service using a Typescript class, like this:

class HelloService {     public getWelcomeMessage():String {         return "Hello";     } }  angular.module('app.services.helloService', []).factory('helloService', () => {     return new HelloService(); }); 

This compiles to the following javascript code:

var HelloService = (function () {     function HelloService() {     }     HelloService.prototype.getWelcomeMessage = function () {         return "Hello";     };     return HelloService; })();  angular.module('app.services.helloService', []).factory('helloService', function () {     return new HelloService(); }); 

This pollutes the global namespace with the variable HelloService, which I obviously don't want. (Using Chrome's console I verified that HelloService was an object.) How can I solve/avoid this problem?

I tried the obvious:

angular.module('app.services.helloService', []).factory('helloService', function () {     class HelloService { ...}      return new HelloService(); }); 

but that gives me a compile error ("Unexpected token; 'statement' expected.").

One possible solution I can think of is using TypeScript's import and export somehow, which in turn will use RequireJS. This probably will wrap the HelloService within a define function, thus avoiding pollution of the global scope with HelloService. However, I don't want to use RequireJS in my AngularJS application for now, as I think AngularJS is good enough for my use, and it adds complexity.

So, my question is, how can I define an AngularJS service using a TypeScript class that doesn't pollute the global scope?

like image 491
Yngvar Kristiansen Avatar asked Oct 18 '13 10:10

Yngvar Kristiansen


People also ask

Can TypeScript be used with AngularJS?

Guide to using TypeScript in AngularJS applications. Supporting older AngularJS applications doesn't mean you can't take advantage of modern tools like TypeScript. Not every file in your application needs to be written in TypeScript at once, you just can rename all your JavaScript files to have a . ts extension.

What is AngularJS TypeScript?

Angular is a modern framework built entirely in TypeScript, and as a result, using TypeScript with Angular provides a seamless experience. The Angular documentation not only supports TypeScript as a first-class citizen, but uses it as its primary language.

Does AngularJS use TypeScript or JavaScript?

First of all, Angular is based on TypeScript while AngularJS is based on JavaScript. TypeScript is a superset of ES6 and it's backward compatible with ES5. Angular has also benefits of ES6 like: lambda operators, iterators or reflection's mechanism. AngularJS uses terms of scope and controller.


2 Answers

2016-05-06: New example using ES6-style modules

The static $inject array and constructor remain unchanged from the previous example.

The only change is to split the classes into multiple files and use ES6 modules to pull in the class definitions.

/lib/HelloService.ts:

export class HelloService {     public getWelcomeMessage():String {         return "Hello from HelloService";     } } 

/lib/AnotherService.ts:

import {HelloService} from './HelloService';  /**  * Service that depends on HelloService.  */ export class AnotherService {      // Define `HelloService` as a dependency.     static $inject = ['HelloService'];     constructor(         // Add the parameter and type definition.         public HelloService: HelloService     ){}      public getWelcomeMessage():String {         // Access the service as: `this.HelloService`         // Enjoy auto-completion and type safety :)         var helloMsg = this.HelloService.getWelcomeMessage();         return "Welcome from AnotherService, " + helloMsg;     } } 

/index.ts:

// Using the services. import {HelloService} from './lib/HelloService'; import {AnotherService} from './lib/AnotherService';  angular.module('HelloApp', [])     .service('HelloService', HelloService)     .service('AnotherService', AnotherService)     .run(['AnotherService', function(AnotherService: AnotherService){         console.log(AnotherService.getWelcomeMessage());     }]); 

Previous answer: using namespaces

Building from Steve Fenton's answer:

To allow dependency injection, add a static $inject array on your class.

See the Angular $injector documentation on how the $inject array works.

The dependencies will be injected into your constructor in the order given by the array (and makes it work with minification).

Dependency Injection Example:

namespace MyModule {     /**      * Angular Service      */     export class HelloService {         public getWelcomeMessage():String {             return "Hello from HelloService";         }     }      /**      * Service that depends on HelloService.      */     export class AnotherService {          // Define `HelloService` as a dependency.         static $inject = ['HelloService'];         constructor(             // Add the parameter and type definition.             public HelloService: MyModule.HelloService         ){}          public getWelcomeMessage():String {             // Access the service as: `this.HelloService`             // Enjoy auto-completion and type safety :)             var helloMsg = this.HelloService.getWelcomeMessage();             return "Welcome from AnotherService, " + helloMsg;         }     } }   // Using the services. angular.module('app.services.helloService', [])     .service('HelloService', MyModule.HelloService)     .service('AnotherService', MyModule.AnotherService)     .run(['AnotherService', function(AnotherService: MyModule.AnotherService){         console.log(AnotherService.getWelcomeMessage());     }]); 
like image 77
Sly_cardinal Avatar answered Sep 29 '22 11:09

Sly_cardinal


I should provide what I actually ended doing:

module MyModule {     export class HelloService {         public getWelcomeMessage():String {             return "Hello";         }     }      angular.module('app.services.helloService', []).factory('helloService', () => {         return new HelloService();     }); } 

In this way I can use

return new HelloService(); 

instead of

return new MyModule.HelloService(); 
like image 30
Yngvar Kristiansen Avatar answered Sep 29 '22 11:09

Yngvar Kristiansen