2014-06-05 15 views
15

Chcę napisać klasę TypeScript, która pobiera parametr "prefix" w konstruktorze, ta klasa również potrzebuje dostępu do iniekcji LogService.Jak zdefiniować fabrykę AngularJS przy użyciu klasy TypeScript, która ma parametry konstruktora?

Korzystanie zwykły JavaScript należy zrobić to tak:

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

Więc kiedy wstrzykiwać tej fabryki do kontrolera, można zainicjować wiele razy tak (nie trzeba wstrzyknąć LOGSERVICE):

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

Jak zdefiniowałbyś tę Fabrykę w klasie TypeScript? Klasy TypeScript nie można zdefiniować w funkcjach ... Ta klasa powinna mieć dostęp do usługi LogService, ale nie może jej pobrać w jednym z iniekcji.

+0

Pokrewne tematy: http://stackoverflow.com/questions/24620275 –

Odpowiedz

13

Dostępne są co najmniej 2 opcje.

Pierwsza opcja, aby LogWithPrefixFactory dostarczyć metodę getInstance, która zwraca prefiksowany program rejestrujący.

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

które mogą być wykorzystane w sterowniku jak:

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

Kompletny plunker here.

Druga opcja (podobna do innej odpowiedzi), daje Angularowi inną funkcję do użycia jako konstruktor, który obsługuje ręcznie iniektor konstruktora LogService (osobiście, nie podoba mi się static).

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

które mogą być wykorzystane w sterowniku jak:

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

lub nawet:

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

LogWithPrefixFactory jest wstrzykiwany w sterowniku, ale to nie jest konstruktor klasy maszynopis, to pośrednia funkcja, która zwraca rzeczywiste wystąpienie klasy, po tym, jak została "ręcznie" wprowadzona jako LogService.

Kompletny plunker here.

Uwaga: Te plunery synchronicznie kompilują maszynopis w przeglądarce. Przetestowałem to tylko w Chrome. Brak gwarancji, że będą działać. Na koniec ręcznie dodałem niewielką część kąta kątowego. Pełny plik był bardzo duży, a mój serwer proxy nie zezwala na duże testy POST.

+0

Tak, owijałem go inną funkcją, która ma tylko potrzebne parametry. – gilamran

+0

Dlaczego te usługi, a nie fabryki? – Hoppe

20

Poniżej jest jednym ze sposobów, aby to osiągnąć:

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: można skutecznie chcą właściwość statyczna w tej LogWithPrefixFactory (stosując zamknięcie w JS), i chcesz to przyjść z Angular.

+0

To jest świetne rozwiązanie! ale Kos podał lepszy sposób. ponieważ jego rozwiązaniem było utrzymywanie klasy wyglądającej tak samo jak zwykła klasa z iniekcjami, a nie stałymi. – gilamran

+2

tutaj nie ma stałych. Tylko statyczne. Statyczny oznacza, że ​​wszystkie instancje klasy mają takie same odwołania do nieinstancji (faktycznie identyczne z działaniem usługi). Jedyna różnica polega na tym, że zamiast statycznych wtryskiwaczy zwracających statyczne usługi współużytkowane przez wszystkie instancje, ma to statyczną usługę bez wtryskiwacza. – FlavorScape

+0

Myślę, że ta odpowiedź jest lepsza, ponieważ jest to fabryka, o jaką prosiłeś. –

1

to w jaki sposób mogę to zrobić

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

Otrzymuję: Typ zwracanej sygnatury konstruktora musi być przypisany do typu instancji klasy. Typ fooFunc :() => ciąg nie nadaje się do wpisania "fooFactory". Literał obiektowy może określać tylko znane właściwości, a fooFunc nie istnieje w typie fooFactory – Nick

1

Ten pracował dla mnie.

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

udało mi się osiągnąć jak poniżej

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

Można utworzyć typ, który pozwala określić, co konstruktor fabryki wygląda następująco:

// 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

Błąd ten jest następujący: "error TS4081: Wyeksportowany alias typu" SelectorFactory "ma lub używa nazwy prywatnej" Selector " – Nick

+0

spróbuj zmienić' Selector klasy' na "Selekcja klasy eksportowej" może? –

Powiązane problemy