2016-01-22 22 views
6

我在解决DI问题方面取得了混合成功。我已经阅读了一些教程,并且我得到了jist,但是在使用我的定制服务制作了一些嵌套的DI之后,事情已经开始崩溃。如何在Angular2中正确使用依赖注入?

有人可以解释何时使用useFactory而不是useClass?我看过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以及如何提供具有其他依赖项的服务?

另外,我在一个地方在我的代码:

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

因为我想有我提供给

@CanActivate(AuthService.isEditorInjector()) 

功能,但我不能使用构造函数注入,因为@ CanActivate超出了范围范围,因此我无法在控制器内部注入服务,然后参考如@CanActivate(this.authService.isEditor())

2.这将是一个很好的解决方案吗?

一些代码:

@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

所以,如果我简单地做:

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删除此错误,但我现在很困惑。这是否意味着deps没有被注入,因为它看不到它们或什么?

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

也许你定义'AuthService'提供商时错过了'HeaderBar'依赖? –

+0

致** 4 **。当你想要DI注入一个具有构造函数参数的类时,你需要添加Injectable注解:@Injectable()导出类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}); 

然后MyService(这对Http依赖)被注入HttpAdvanced代替。 确保您在HTTP_PROVIDERS之后拥有此行以覆盖HTTP_PROVIDERS中包含的默认Http提供程序。

如果DI本身不能解决依赖关系,因为它们不仅仅是其他提供者,而是使用useFactory

如上所述,

确保您有HTTP_PROVIDERS后,这条线来覆盖默认Http供应商,包含在HTTP_PROVIDERS

提供者列表中的顺序确实很重要。 当提供者列表包含一个类型的多个提供者时,则只使用最后一个提供者。

订单进口无所谓。

一个文件内的依赖类的顺序确实是,因为类没有被挂起。

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

export class ClassB { 
} 

如果ClassB代码是上述ClassAforwardRef()是没有必要的。

又见Class is not injectable if it is defined right after a component with meta annotation

+0

我对没有足够的信息表示歉意,我不想用冗余代码污染。问题是我没有提供HttpAdvanced而不是通常的Http,这是我提供的HttpAdvanced类像HttpAdvanced {构造函数(HTTP:Http){this.http = http; }}我也提供HttpAdvnced给其他组件,但不是Http,而是它本身。我会添加一些代码 – ditoslav

+0

没问题,我明白这是一个迭代过程。在这种情况下,只需用'HttpAdvanced'替换'提供(Http,{useClass:HttpAdvanced});''。 –

+0

我在什么时候编写'provide(HttpAdvanced,{useClass:HttpAdvanced})',我什么时候在你的例子中编写'HttpAdvanced'就像使用MsgService – ditoslav

4

要完成一个位的君特的伟大和明确的答案,我会说,我会用useFactory通过自己与供应商相关的类实例在以下案例:

  • 当您想要选择要注入与提供者关联的元素的构造函数的元素时。例如,如果要扩展HTTP类并明确提供参数的具体具体类(这里是XHRBackend而不是ConnectionBackend)。下面是一个示例:

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

@Langley提供了在这个问题有意思提示:Handling 401s globally with Angular

  • useFactory的另一个凉爽用法是实例化来自第三方库的一类成Angular2的上下文中(区域)

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

@alexpods提供在这个非常简洁的解决方案这个问题:View is not updated on change in Angular2

希望它可以帮助你, 蒂埃里