我在解决DI问题方面取得了成功。我已经阅读了一些教程并获得了jist但是在使用我的自定义服务进行了一些嵌套的DI后,事情开始崩溃了。
有人可以解释何时使用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。 我是否正确使用了provide / 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依赖于Internal,我之前必须放置Internal但是我不是100%它是否与importing
的顺序相同? / p>
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
删除此错误,但我现在感到困惑。这是否意味着没有注入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 :(得分: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
中包含的默认HTTP_PROVIDERS
提供商。
如果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
的代码高于ClassA
,则forwardRef()
是不必要的。
另见Class is not injectable if it is defined right after a component with meta annotation
答案 1 :(得分:4)
为了完成Günter的明确答案,我会说在以下用例中我会使用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(Zones)的上下文中
bootstrap(App, [
provide(Mousetrap, { useFactory: () => new Mousetrap() })
]);
@alexpods在这个问题中提供了这个非常优雅的解决方案:View is not updated on change in Angular2。
希望它可以帮到你, 亨利