I have had mixed success with resolving issues with DI. I have read a few tutorials and I get the jist but after making some nested DIs with my custom services things have started to fall apart.
Could someone explain when to use useFactory instead of useClass? I have seen the ng2 docs and I have seen the examples but I cannot map them to my problems. Currently my bootstrapper looks like this:
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 })
]
);
And my latest issue is:
EXCEPTION: Error during instantiation of AuthService! (HeaderBar -> AuthService).
ORIGINAL EXCEPTION: TypeError: this.http.get is not a function
My dependencies work like
HttpAdvanced -> Http(ng2), MsgService
MsgService -> MsgServiceInternal
AuthService -> HttpAdvanced
FormBuilderAdvanced -> FormBuilder(ng2), HttpAdvanced
1. Am I properly using provide / useClass / useFactory and how do I provide services that have other dependencies?
Also, I have at one place in my code:
static isUserInjector() {
return (next, prev) => Injector.resolveAndCreate([AuthService, provide(HttpAdvanced, { useClass: HttpAdvanced })]).get(AuthService).isUser();
}
Because I want to have a function that I provide to
@CanActivate(AuthService.isEditorInjector())
but I can't use constructor injection because @CanActivate is outside of the class scope so I can't inject the service inside the controller and then reference like @CanActivate(this.authService.isEditor())
2. What would be a good solution for this?
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.
Does the order of importing files matter for DI? I think i noticed that since I have MsgService and MsgServiceInternal in the same file and MsgService depends on Internal that I had to put Internal before but I'm not 100% Is it the same of order of importing
?
4. So if I simply do:
bootstrap(
App,
[
FORM_PROVIDERS,
ROUTER_PROVIDERS,
HTTP_PROVIDERS,
provide(LocationStrategy, { useClass: PathLocationStrategy }),
provide(RequestOptions, { useClass: DefaultRequestOptions }),
MsgService,
HttpAdvanced,
AuthService,
FormBuilderAdvanced,
MsgServiceInternal
]
);
I get:
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.
I used to remove this error with the useFactory
but I'm confused now. Does this mean the deps aren't injected because it can't see them or what?
The Form class:
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);
}
}