2016-01-22 20 views
6

私はDIとの問題を解決することに成功しました。私はいくつかのチュートリアルを読んで、ジストを取得しますが、カスタムサービスでいくつかのネストされたDIを作成した後、物事は崩壊し始めました。Angular2で依存関係注入を正しく使うには?

誰かがuseClassではなくuseFactoryをいつ使用するか説明できますか?私はng2のドキュメントを見て、私は例を見ましたが、私はそれらを私の問題にマップすることはできません。現在、私のブートストラップは、次のようになります。

bootstrap(
    App, 
    [ 
     FORM_PROVIDERS, 
     ROUTER_PROVIDERS, 
     HTTP_PROVIDERS, 
     provide(LocationStrategy, { useClass: PathLocationStrategy }), 
     provide(RequestOptions, { useClass: DefaultRequestOptions }), 
     provide(MsgService, { useClass: MsgService }), 
     provide(HttpAdvanced, { useFactory: (MsgService, HTTP_PROVIDERS) => new HttpAdvanced(MsgService, HTTP_PROVIDERS), deps: [MsgService, HTTP_PROVIDERS] }), 
     provide(AuthService, { useFactory: (HttpAdvanced) => new AuthService(HttpAdvanced), deps: [HttpAdvanced, HTTP_PROVIDERS, MsgService] }), 
     provide(FormBuilderAdvanced, { useFactory: (FormBuilder, HttpAdvanced) => new FormBuilderAdvanced(FormBuilder, HttpAdvanced), deps: [FormBuilder, HttpAdvanced] }), 
     provide(MsgServiceInternal, { useClass: MsgServiceInternal }) 
    ] 
); 

そして、私の最新号は、次のとおりです。

EXCEPTION: Error during instantiation of AuthService! (HeaderBar -> AuthService). 
ORIGINAL EXCEPTION: TypeError: this.http.get is not a function 

は私の依存関係が

HttpAdvanced  -> Http(ng2), MsgService 
MsgService   -> MsgServiceInternal 
AuthService   -> HttpAdvanced 
FormBuilderAdvanced -> FormBuilder(ng2), HttpAdvanced 

1.のように動作し、私は適切に提供し使用しています/ useClass/useFactoryと他の依存関係を持つサービスを提供するには?私は

@CanActivate(AuthService.isEditorInjector()) 

に提供機能を持つようにしたいが、私はので、コンストラクタ・インジェクションを使用することはできませんので

static isUserInjector() { 
    return (next, prev) => Injector.resolveAndCreate([AuthService, provide(HttpAdvanced, { useClass: HttpAdvanced })]).get(AuthService).isUser(); 
} 

@:

はまた、私は自分のコード内の1つの場所で持っていますCanActivateはクラススコープ外にあるため、コントローラ内にサービスを挿入してから参照することはできません。@CanActivate(this.authService.isEditor())

2.これにはどのような良い解決策がありますか?

SOME CODE:

@Component({ 
    selector: 'ShowStats', 
    templateUrl: './dest/views/showStats/showStats.html', 
    directives: [ COMMON_DIRECTIVES, UsersCount, AdminsList, GlobalWishlist, PopularTrack ] 
}) 
export class ShowStats { 
    authService : AuthService; 

    constructor(authService : AuthService){ 
     this.authService = authService; 
    } 
} 

... next file ... 

@Injectable() 
export class HttpAdvanced { 
    msgService: MsgService; 
    http: Http; 

    constructor(msgService: MsgService, http: Http) { 
     this.msgService = msgService; 
     this.http = http; 
    } 

    /* 
    * This is for plain ol' GET requests .. with callback of course. 
    */ 
    public get(url, callback) { 
     return this.http.get(url).subscribe((res) => { 
      let data = res.json().data; 
      callback(data); 
     }, this.msgService.httpErrorHandler); 
    } 
.... other code for HttpAdvanced 

3. ファイルをインポートするためには、DIのために重要ですか?私は私がMsgServiceとMsgServiceInternalを同じファイルに持っていてMsgServiceが内部に依存していることに気付いたと思いますが、私は内部を入れなければなりませんでしたが、私は100%ではありませんimportingの順序は同じですか?

4. だから私は単純に行う場合:

bootstrap(
    App, 
    [ 
     FORM_PROVIDERS, 
     ROUTER_PROVIDERS, 
     HTTP_PROVIDERS, 
     provide(LocationStrategy, { useClass: PathLocationStrategy }), 
     provide(RequestOptions, { useClass: DefaultRequestOptions }), 
     MsgService, 
     HttpAdvanced, 
     AuthService, 
     FormBuilderAdvanced, 
     MsgServiceInternal 
    ] 
); 

私が取得:

Cannot resolve all parameters for 'FormBuilderAdvanced'(?, ?). 
Make sure that all the parameters are decorated with Inject or have 
valid type annotations and that 'FormBuilderAdvanced' is decorated 
with Injectable. 

私はuseFactoryと、このエラーを除去するために使用されるが、私は今、混乱しています。これは、彼らが何かを見ることができないためにデンプスが注射されないということですか?

Formクラス:あなたがのためにクラスを利用できるようにしたい場合は

export class FormBuilderAdvanced { 
    http: HttpAdvanced; 
    fb: FormBuilder; 

    constructor(fb: FormBuilder, http: HttpAdvanced) { 
     this.fb = fb; 
     this.http = http; 
    } 

    create(controlNames: string[], submissionUrl: string, getter?: any) { 
     return new Form(this.fb, this.http, controlNames, submissionUrl, getter); 
    } 
} 
+0

はおそらく、あなたは' HeaderBar'依存性を逃したホープ? –

+0

** ** **。 DIがコンストラクタパラメータを持つクラスを挿入したい場合は、 'Injectable'アノテーションを追加する必要があります:' @Injectable()export class FormBuilderAdvanced {'。あなたの場合、別の問題があります。 DIは 'controlNames:string []、submissionUrl:string、getter ?: any'を解決できません。 'string []'または 'any'のプロバイダはありません。ここでコンストラクタに何を渡したいのですか?おそらくこれは 'useValue'や' useFactory'の場合です。 –

+0

ああ私はどこにでも置いている。この愚かだったと信じられない – ditoslav

答えて

6

あなたの質問には確実に知るために十分な情報を提供していませんが、これはおそらく

bootstrap(
    App, 
    [ 
     FORM_PROVIDERS, 
     ROUTER_PROVIDERS, 
     HTTP_PROVIDERS, 
     provide(LocationStrategy, { useClass: PathLocationStrategy }), 
     provide(RequestOptions, { useClass: DefaultRequestOptions }), 
     // provide(MsgService, { useClass: MsgService }), 
     MsgService, // is just fine when no special behavior is required 
     // provide(HttpAdvanced, { useFactory: (MsgService, HTTP_PROVIDERS) => new HttpAdvanced(MsgService, HTTP_PROVIDERS), deps: [MsgService, HTTP_PROVIDERS] }), 
     provide(Http, {useClass: HttpAdvanced}); 
     AuthService, 
     provide(FormBuilder, { useClass: FormBuilderAdvanced}), 
     MsgServiceInternal) 
    ] 
); 

十分です注射、ちょうどプロバイダのリスト(provide(AuthService)とちょうどAuthService同じを行う)にタイプを追加します。 要求されたクラスと異なるクラスを注入する場合は、useClassを使用してください。

@Injectable() 
export class MyService { 
    constructor(private http: Http) { 
    } 
} 

あなたのプロバイダは

provide(Http, {useClass: HttpAdvanced}); 

が含まれている場合は、MyServiceHttpに依存していた)を注入しますHttpAdvanced代わりに。 HTTP_PROVIDERSのデフォルトのHttpプロバイダーを上書きするには、HTTP_PROVIDERSの後にこの行があることを確認してください。

DIが他のプロバイダではないため、依存関係を単独で解決できない場合は、useFactoryを使用します。

前述したように、

HTTP_PROVIDERSに含まれるデフォルトHttpプロバイダを、上書きするHTTP_PROVIDERS後にこのラインを持っていることを確認します。

プロバイダのリスト内の順序は重要です。 プロバイダリストに型のプロバイダが複数含まれている場合は、最後のプロバイダのみが使用されます。

の順番は関係ありません。

1つのファイル内の依存クラスの順序は、クラスが吊り上げられないため、になります。

export class ClassA { 
    // constructor(private b: ClassB) {} // ClassB is unknown here 
    constructor(@Inject(forwardRef(() => DataService)) { 
    } 
} 

export class ClassB { 
} 

ClassBのコードはforwardRef()を必要としない、ClassA上回る場合。

ビットにギュンターの偉大なと明確な答えを完了するためにもClass is not injectable if it is defined right after a component with meta annotation

+0

私は十分な情報がないことをお詫びします。私は冗長コードで汚染することを心配していませんでした。問題は、通常のHttpの代わりにHttpAdvancedを提供していないことです。HttpAdvancedクラスのようなHttpAdvancedにHttpを提供していることです(コンストラクタ(http:Http){this.http = http; }}また、HttpAdvncedを他のコンポーネントにも提供していますが、Httpではなく、それ自体で提供しています。私はいくつかのコードを追加します – ditoslav

+0

問題はありません、私はこれが反復プロセスであることを理解しています。この場合は、 'HttpAdvanced'によって' provide(Http、{useClass:HttpAdvanced}); 'を置き換えてください。 –

+0

いつ 'provide(HttpAdvanced、{useClass:HttpAdvanced}) 'を書くのですか?あなたの例でMsgServiceのような' HttpAdvanced'をいつ書くのですか? – ditoslav

4

を参照してください、私は自分で次の使用例ではプロバイダに関連付けられたクラスをインスタンス化するuseFactoryを使用すると言うでしょう:

  • プロバイダに関連付けられている要素のコンストラクタに挿入する要素を選択する場合。たとえば、HTTPクラスを拡張し、パラメータの具体的な具体的なクラス(具体的にはConnectionBackendではなくXHRBackend)を明示的に指定する場合は、ここにサンプルがある:Handling 401s globally with Angular

    bootstrap(AppComponent, [HTTP_PROVIDERS, ROUTER_PROVIDERS, 
        new Provider(Http, { 
        useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => new CustomHttp(backend, defaultOptions), 
        deps: [XHRBackend, RequestOptions] 
        }) 
    ]); 
    

@Langleyこの質問に興味深いヒントを提供します。

  • useFactoryの別のクールな使用はAngular2のコンテキストに、サードパーティのライブラリからクラスをインスタンス化(ゾーン)

    bootstrap(App, [ 
        provide(Mousetrap, { useFactory:() => new Mousetrap() }) 
    ]); 
    

@alexpodsは、この非常にエレガントな解決策を提供していますこの質問:View is not updated on change in Angular2

は、それが `AuthService`プロバイダを定義するときに、 ティエリー

関連する問題