J'ai un service parent qui a des dépendances comme
@Injectable()
export class ParentService{
constructor(private http:Http, private customService:CustomService){}
}
et je veux étendre le service
@Injectable()
export class ChildService extends ParentService{
constructor (){
super(??) <= TypeScript now asking to enter two parameters according to ParentServie's constructor
}
}
Modifier -----------------
@Injectable()
export class ParentService{
constructor(private http:Http, private customService:CustomService){}
get(){this.http.get(...)}
}
@Injectable()
export class ChildService extends ParentService{
constructor (private http:Http, private customService:CustomService){
super(http, customService)
}
}
Ensuite, je peux utiliser dans les composants?
export class Cmp {
constructor(private childService:ChildService){
this.childService.get()
}
}
Les paramètres de la super classe doivent être répétés et transmis au super appel:
@Injectable()
export class ChildService extends ParentService{
constructor (http:Http, customService:CustomService){
super(http, customService);
}
}
Il y a quelques "hacks" à contourner comme Inheritance and dependency injection
Faites simplement le service de base ... non -@Injectable()
! Par exemple, vous devez fournir une méthode pour récupérer le profil utilisateur dans LoginService
. Cette méthode sera différente pour différentes instances de LoginService
, et la classe parente ne doit rien savoir d'où vient cette méthode: il peut s'agir de lambda, il peut être une fonction exportée, il peut s'agir d'une méthode d'un autre service. Pour ce faire, vous pouvez déclarer le service parent quel service parent:
// 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
}
Ensuite, étendez-le dans la classe enfant:
// 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
}
Remarque: dans la section providers
du module, spécifiez LoginService
au lieu du parent BaseLoginService
:
providers: [
LoginService,
et l'utiliser dans les classes de composants:
export class LoginComponent implements OnInit {
constructor(
private loginService: LoginService
) {
}
Si vous devez utiliser le service parent (par exemple dans les composants partagés qui n'ont besoin que de fonctionnalités de la classe de service parent), fournissez BaseLoginService
de cette façon:
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
Si vous créez les services DI dans la classe abstraite protected
et omettez le constructeur dans la sous-classe, alors les services sont disponibles dans la sous-classe.