2014-06-05 6 views
15

Ich möchte eine TypeScript-Klasse schreiben, die einen "Präfix" -Parameter im Konstruktor erhält, diese Klasse benötigt auch Zugriff auf einen LogService inject.Wie kann ich eine AngularJS-Factory mit TypeScript-Klasse definieren, die Konstruktorparameter hat

Ebene JavaScript verwenden, sollten Sie es wie folgt tun:

angular.module('myModule', []).factory('LogWithPrefixFactory', ['LogService', function(LogService) { 
    var LogWithPrefixFactory = function(prefix) { 
     this.prefix = prefix; 
    } 

    LogWithPrefixFactory.prototype.log = function(txt) { 
     // we have access to the injected LogService 
     LogService.log(this.prefix, txt); 
    } 

    return LogWithPrefixFactory; 
}]); 

Also, wenn Sie diese Fabrik an einen Controller injizieren, können Sie es oft wie diese auslösen kann (keine Notwendigkeit, die LogService zu injizieren):

Wie würden Sie diese Factory in einer TypeScript-Klasse definieren? TypeScript-Klassen können nicht innerhalb von Funktionen definiert werden ... Diese Klasse sollte Zugriff auf den LogService haben, aber sie kann ihn nicht in einer der injects bekommen.

+0

Verwandtes Thema: http://stackoverflow.com/questions/24620275 –

Antwort

13

Es gibt mindestens 2 Optionen.

Erste Option, haben LogWithPrefixFactory bieten eine Methode getInstance, die den vorfixierten Logger zurückgibt.

module services { 
    class LogService { 
    $window: any; 

    constructor($window: any) { 
     this.$window = $window; 
    } 

    log(prefix: string, txt: string) { 
     this.$window.alert(prefix + ' :: ' + txt); 
    } 
    } 
    angular.module('services').service('LogService', ['$window', LogService]); 


    export interface ILog { 
    log: (txt) => void; 
    } 

    export class LogWithPrefixFactory { 
    logService: LogService; 

    constructor(logService: LogService) { 
     this.logService = logService; 
    } 

    getInstance(prefix: string): ILog { 
     return { 
     log: (txt: string) => this.logService.log(prefix, txt); 
     } 
    } 
    } 

    angular.module('services').service('LogWithPrefixFactory', ['LogService', services.LogWithPrefixFactory]); 
} 

die in der Steuerung wie verwendet werden können:

this.log1 = logWithPrefixFactory.getInstance("prefix1"); 
this.log2 = logWithPrefixFactory.getInstance("prefix2"); 

komplette Plunker here.

Zweite Option (ähnlich einer anderen Antwort), geben Angular eine andere Funktion als Konstruktor verwendet werden, die manuell die LogService Konstruktor Injektion behandelt (persönlich, mag ich nicht static).

angular.module('services').service('LogWithPrefixFactory', ['LogService', function(logService) { 
    return function LogWithPrefixFactory(prefix) { 
     return new LogWithPrefix(prefix, logService); 
    }; 
}]); 

die in der Steuerung wie verwendet werden können:

this.log1 = new LogWithPrefixFactory("prefix1"); 
this.log2 = new LogWithPrefixFactory("prefix2"); 

oder sogar:

this.log1 = LogWithPrefixFactory("prefix1"); 
this.log2 = LogWithPrefixFactory("prefix2"); 

LogWithPrefixFactory in der Steuerung eingespritzt, aber es ist nicht das Typoskript Klassenkonstruktors, es ist die Zwischen Funktion, die die tatsächliche Instanz der Klasse zurückgibt, nachdem sie "manuell" mit LogService injiziert wurde.

Kompletter Kolben here.

Hinweis: Diese Plunker kompilieren im Browser syntaktisch Typoskript. Ich habe es nur in Chrome getestet. Keine Garantie, dass sie funktionieren. Schließlich habe ich manuell einen kleinen Teil von angular.d.ts hinzugefügt. Die vollständige Datei war sehr groß und mein Proxy erlaubt keine großen POSTs.

+0

Ja, ich habe es mit einer anderen Funktion verpackt, die nur die benötigten Parameter enthält. – gilamran

+0

Warum sind diese Dienste und keine Fabriken? – Hoppe

20

Das folgende ist eine Möglichkeit, dies zu erreichen:

class LogWithPrefixFactory { 
    static LogService; 
    constructor(prefix) { 
     this.prefix = prefix; 
    } 

    log = function(txt) { 
     // we have access to the injected LogService 
     LogService.log(this.prefix, txt); 
    } 
} 

angular.module('myModule', []).factory('LogWithPrefixFactory', ['LogService', function(LogService) { 
    LogWithPrefixFactory.LogService = LogService; 
    return LogWithPrefixFactory; 
}]); 


angular.module('myModule').controller('Ctrl', function(LogWithPrefixFactory) { 
    var foo = new LogWithPrefixFactory("My PREFIX"); 
    var foo = new LogWithPrefixFactory("My OTHER PREFIX"); 
}); 

Rational: Sie wollen effektiv eine statische Eigenschaft in einem der LogWithPrefixFactory (einen Verschluss in JS verwenden), und Sie wollen es kommen von Angular.

+0

Dies ist eine großartige Lösung! aber Kos gab einen besseren Weg. weil seine Lösung darin bestand, dass die Klasse genauso aussah wie eine reguläre Klasse mit Injektionen und nicht mit Konflikten. – gilamran

+2

gibt es hier keine Konstanten. Nur statisch. Statisch bedeutet nur, dass alle Instanzen der Klasse den gleichen Nicht-Instanz-Verweis teilen (effektiv identisch mit der Funktionsweise eines Dienstes). Der einzige Unterschied besteht hier darin, dass anstelle eines statischen Injektors, der von allen Instanzen gemeinsam genutzte statische Dienste zurückgibt, ein statischer Dienst ohne den Injektor vorhanden ist. – FlavorScape

+0

Ich denke, diese Antwort ist besser, weil es eine Fabrik ist, wie Sie gefragt haben. –

1

das ist, wie ich es tun

namespace app { 
      let app =angular.module('foo',[]); 
       app.factory(factories);//for registering whatever is there in factories namespace 

     } 

namespace app.factories { 


export class fooFactory { 

    static $inject = ['fooHelperService'] 
    constructor(fooHelperService: services.fooHelperService) { 

     return { 

      fooFunc:() => { 

       return 'hellow world' 
      } 
     } 
    } 
} 

} 
+0

Ich bekomme: Rückgabetyp der Konstruktorsignatur muss dem Instanztyp der Klasse zuweisbar sein. Type fooFunc :() => String ist nicht dem Typ 'fooFactory' zuweisbar. Objektliteral darf nur bekannte Eigenschaften angeben, und fooFunc existiert nicht im Typ fooFactory – Nick

1

Das ist für mich gearbeitet.

namespace Services 
    { 
     export class MyService 
     { 
     constructor(protected $someService :any) 
     { 
      return this; 
     } 
     } 
    } 
    angular.module('myModule', []).factory(Services); 
3

Ich habe wie erreicht unter

module Dashboard { 
    export class LayoutServiceFactory { 
     static $inject = ["$q", "$http"]; 
     private q: ng.IQService; 
     private http: ng.IHttpService; 

     constructor(private $q: ng.IQService, private $http: ng.IHttpService) { 
      this.q = $q; 
      this.http = $http; 
     } 

     getDataFromServer(serviceUrl) { 
      var deferred = this.q.defer(); 
      this.http.get(serviceUrl, null) 
       .then(response => { 

        deferred.resolve((response) as any); 

       }); 
      return deferred.promise; 
     } 

     static factory() { 
      var instance = ($q: ng.IQService, $http: ng.IHttpService) => 
       new LayoutServiceFactory($q, $http); 
      return instance; 
     } 
    } 

    appModule.factory("LayoutService", LayoutServiceFactory.factory()); 
} 
1

Sie einen Typ erstellen können, die Sie, was der Konstruktor der Fabrik ermöglicht die Definition wie folgt aussieht:

// Defining the factory 

// THIS IS THE IMPORTANT PART!! 
export type SelectorFactory = new (config: any) => Selector; 

export class Selector { 

    constructor(protected config: any, protected $http: ng.IHttpService) { 
     // do some stuff 
    } 
} 

angular.module('app') 
    .factory('Selector', ($http: ng.IHttpService) => { 
     // This is what the factory looks like to the end user 
     return (config: any) => { 
      return new Selector(config, $http); 
     }; 
    }); 

// Using the factory 
export class SampleCtrl { 
    constructor(public SelectorFactory: SelectorFactory) { 
     let config = { op: 1 }; 

     let selector: Selector = new SelectorFactory(config); 
    } 
} 
+0

. Der Fehler dabei ist: "Fehler TS4081: Exportierter Typalias 'SelectorFactory' hat oder verwendet den privaten Namen 'Selector' – Nick

+0

versuchen Sie' class Selector' zu ändern 'export class Selector' vielleicht? –

Verwandte Themen