Как расширить компонент с помощью внедрения зависимостей?
У меня есть следующий класс ModuleWithHttp
:
@Injectable()
export default class {
constructor(private fetchApi: FetchApi) {}
}
и я хочу использовать его следующим образом:
@Component({
selector: 'main',
providers: [FetchApi]
})
export default class extends ModuleWithHttp {
onInit() {
this.fetchApi.call();
}
}
Поэтому, расширяя суперкласс, который уже внедряет зависимость, я хочу иметь доступ к нему в его дочерних элементах.
Я пробовал много разных способов, даже имея супер-класс в качестве компонента:
@Component({
providers: [FetchApi]
})
export default class {
constructor(private fetchApi: FetchApi) {}
}
Но все же this.fetchApi
является null
, даже в суперклассе.
Ответы
Ответ 1
Вы должны ввести fetchAPI в суперкласс и передать его дочернему классу
export default class extends ModuleWithHttp {
constructor(fetchApi: FetchApi) {
super(fetchApi);
}
onInit() {
this.fetchApi.call();
}
}
Это особенность работы DI в целом. Суперкласс будет инстанцировать ребенка через наследование, но вы должны предоставить необходимые параметры ребенку.
Ответ 2
Если вы хотите избежать использования кода "котельной пластины" для инъекций в дочерних классах только для инъекций в конструкторе родительских классов, а затем эффективно использовать эти сервисы в дочерних классах через наследование, вы можете сделать это:
edit: от Angular 5.0.0 ReflectiveInjector устарел в пользу StaticInjector, ниже обновлен код, чтобы отразить это изменение
У вас есть карта услуг с папками,
export const services: {[key: string]: {provide: any, deps: any[], useClass?: any}} = {
'FetchApi': {
provide: FetchApi,
deps: []
}
}
Держите держатель инжектора,
import {Injector} from "@angular/core";
export class ServiceLocator {
static injector: Injector;
}
настройте его в AppModule,
@NgModule(...)
export class AppModule {
constructor() {
ServiceLocator.injector = Injector.create(
Object.keys(services).map(key => ({
provide: services[key].provide,
useClass: services[key].provide,
deps: services[key].deps
}))
);
}
}
используйте инжектор в родительском классе,
export class ParentClass {
protected fetchApi: FetchApi;
constructor() {
this.fetchApi = ServiceLocator.injector.get(FetchApi);
....
}
}
и расширьте родительский класс, поэтому вам не нужно вводить службу FetchApi
.
export class ChildClass extends ParentClass {
constructor() {
super();
...
}
onInit() {
this.fetchApi.call();
}
}
Ответ 3
Возможно, поздний ответ, но я решил внедрить только инжектор в BaseComponent и во всех подклассах, таким образом мне не нужно поддерживать указатель службы.
Мой базовый класс:
constructor(private injectorObj: Injector) {
this.store = <Store<AppState>>this.injectorObj.get(Store);
this.apiService = this.injectorObj.get(JsonApiService);
this.dialogService = this.injectorObj.get(DialogService);
this.viewContainerRef = this.injectorObj.get(ViewContainerRef);
this.router = this.injectorObj.get(Router);
this.translate = this.injectorObj.get(TranslateService);
this.globalConstantsService = this.injectorObj.get(GlobalConstantsService);
this.dialog = this.injectorObj.get(MatDialog);
this.activatedRoute = this.injectorObj.get(ActivatedRoute);
}
Мои детские классы:
constructor( private injector: Injector) {
super(injector);
}
Ответ 4
Вы можете внедрить любой сервис или класс из родительского класса с помощью класса Injector
, вам нужно внедрить класс Injector
из дочернего объекта и передать его родителю с помощью super(injector)
чтобы родитель мог внедрить ваши повторно используемые услуги из инжектора, исходящего от дочернего элемента.
Родительский класс:
export class BaseComponent implements OnInit {
protected myService: MyService
constructor(injector: Injector) {
this.myService = injector.get(MyService)
}
ngOnInit() {
console.log('ngOnInit from Base');
}
}
Детский класс:
export class AppComponent extends BaseComponent {
constructor(injector: Injector) {
super(injector)
}
ngOnInit() {
super.ngOnInit()
this.myService.getUsers()
}
}
Используя этот способ, вы не хотите внедрять каждую службу от дочерней, чтобы передавать одну за другой родителю, вышеуказанный способ более эффективен для внедрения от родительской.
форсунка
import { Component, Injector } from '@angular/core';