webentwicklung-frage-antwort-db.com.de

Wie kann ich einen AngularJS-Dienst mit einer TypeScript-Klasse definieren, die den globalen Bereich nicht verschmutzt?

Ich benutze AngularJS und TypeScript. Ich möchte einen AngularJS-Dienst mit einer TypeScript-Klasse wie folgt implementieren:

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

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

Dies kompiliert mit dem folgenden 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();
});

Dadurch wird der globale Namespace mit der Variablen HelloService verschmutzt, was ich offensichtlich nicht möchte. (Mit der Chrome-Konsole habe ich festgestellt, dass HelloService ein Objekt ist.) Wie kann ich dieses Problem lösen/vermeiden?

Ich habe das Offensichtliche versucht:

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

aber das gibt mir einen Kompilierungsfehler ("Unerwartetes Token; 'Anweisung' erwartet.").

Eine mögliche Lösung, die ich mir vorstellen kann, ist der Import und Export von TypeScript, der wiederum RequireJS verwendet. Dies wird den HelloService wahrscheinlich in eine definierte Funktion einschließen, wodurch eine Verschmutzung des globalen Gültigkeitsbereichs mit HelloService vermieden wird. Derzeit möchte ich RequireJS jedoch nicht in meiner AngularJS-Anwendung verwenden, da AngularJS meiner Meinung nach für meine Zwecke gut genug ist und die Komplexität erhöht.

Meine Frage ist also, wie ich einen AngularJS-Dienst mit einer TypeScript-Klasse definieren kann, die den globalen Bereich nicht verschmutzt.

35

Ich sollte angeben, was ich eigentlich getan habe:

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

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

Auf diese Weise kann ich nutzen

return new HelloService();

anstatt von

return new MyModule.HelloService();
14

2016-05-06: Neues Beispiel mit ES6-ähnlichen Modulen

Das statische $inject - Array und der Konstruktor bleiben gegenüber dem vorherigen Beispiel unverändert.

Die einzige Änderung besteht darin, die Klassen in mehrere Dateien aufzuteilen und die Klassendefinitionen mithilfe von ES6-Modulen abzurufen.

/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());
    }]);

Vorherige Antwort: Verwenden von Namespaces

Aufbauend auf Steve Fentons Antwort :

Fügen Sie Ihrer Klasse ein statisches $inject - Array hinzu, um die Abhängigkeitsinjektion zuzulassen.

Lesen Sie in der Dokumentation zu Angular $ injector nach, wie das Array $inject Funktioniert.

Die Abhängigkeiten werden in der vom Array angegebenen Reihenfolge in Ihren Konstruktor eingefügt (und funktionieren mit Minimierung).

Beispiel für die Abhängigkeitsinjektion:

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());
    }]);
34
Sly_cardinal

Ich habe zwei Lösungen, die erste gibt Ihnen klassenbasierte Syntax, die zweite lässt absolut nichts im globalen Rahmen ...

Sie könnten geringfügige Kompromisse eingehen, indem Sie dem globalen Bereich nur ein einziges Handle hinzufügen (dies gilt wirklich, wenn Sie mehrere Klassen haben, die Sie nicht in den globalen Bereich einfügen möchten, da Sie derzeit nur eine Klasse haben).

Der folgende Code belässt nur das Modul im globalen Bereich.

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

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

}

angular.module('app.services.helloService', []).factory('helloService', () => {
    return new MyModule.HelloService();
});

angular.module('app.services.anotherService', []).factory('anotherService', () => {
    return new MyModule.AnotherService();
});

Alternativ können Sie die Klassensyntax umgehen und "einfaches altes JavaScript" verwenden, um keine einzige Sache im globalen Bereich zu belassen:

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

    return new HelloService();
});
6
Fenton