how to extend service with dependencies in angular 2
Simply make base service... non-@Injectable()
! For example, you need to supply a method to retrieve user profile in LoginService
. This method will be different for different instances of LoginService
, and parent class must not know anything about where from this method came: it can be lambda, it can be exported function, it can be a method of another service. To achieve this, you can declare parent service which
Parent service:
// Don't annotate it with @Injectable() ! It's a simple class.
export abstract class BaseLoginService {
constructor(
// This won't be injected automatically,
// child class must call super() and provide value for this argument.
// Note: it's private, can't be accessed outside of BaseLoginService class
private http: HttpClient,
// Method used to retrieve user profile
private profileGetter: () => Observable<UserDetails>,
private router: Router
) {
this.profileGetter().subscribe(); // Do something with this method
}
Then extend it in child class:
// Child class must be annotated with @Injectable(),
// if you don't need to extend it further
@Injectable()
export class LoginService extends BaseLoginService {
constructor(
// Note: no public/private/protected here - "http"
// will be just an argument
http: HttpClient,
private profileService: ProfileService, // This is the private field of LoginService class
router: Router,
// Some service used by LoginService class, parent class BaseLoginService
// doesn't need to know about SomeOtherService
private someOtherService: SomeOtherService
) {
super(
http,
// Need lambda here to capture profileService instance. If
// profileService.getUserDetailsMethod doesn't use instance
// fields or methods, then we can simply write
// "profileService.getUserDetailsMethod" (without quotes, obviously).
() => profileService.getUserDetailsMethod(),
router
);
this.someOtherService.doSomething(); // Custom initialization code
}
Note: in providers
section of module specify LoginService
instead of parent BaseLoginService
:
providers: [
LoginService,
and use it in component classes:
export class LoginComponent implements OnInit {
constructor(
private loginService: LoginService
) {
}
If you need to use parent service (e.g. in shared components which only need functionality from parent service class), then provide BaseLoginService
this way:
providers: [
{provide: BaseLoginService, useExisting: LoginService}, // For those components which need functionality from base class only
LoginService, // Still need this one for those components which need functionality from child class
The parameters of the super class need to be repeated and passed to the super call:
@Injectable()
export class ChildService extends ParentService{
constructor (http:Http, customService:CustomService){
super(http, customService);
}
}
There are some "hacks" to work around like Inheritance and dependency injection