Reputation: 376
I need a base component from which my other components can extend. The Parent components have all different services with extend from the same service and I want to pass this services to the Base component, so it can do its work.
Right now I am extending the base component from my Parent component and then try load the service via an injector token which I provide in the Parent component and the parent components module (i just trier both because it didn't work).
But I get an:
ERROR NullInjectorError: R3InjectorError(fe)[InjectionToken ENTITYLISTSERVICEPROVIDER -> InjectionToken ENTITYLISTSERVICEPROVIDER -> InjectionToken ENTITYLISTSERVICEPROVIDER]:
NullInjectorError: No provider for InjectionToken ENTITYLISTSERVICEPROVIDER!
everytime and dont know what to do.
My Parent component looks like this:
@Component({
selector: 'app-recording-data-entry-form',
templateUrl: './recording-data-entry-form.component.html',
styleUrls: ['./recording-data-entry-form.component.scss'],
providers: [
{ provide: ENTITYLISTSERVICE_PROVIDER, useClass: RecordingsService },
{ provide: ENTITYENDPOINT_PROVIDER, useValue: 'apiEndpoints.RECORDING' },
{ provide: ENTITY_FORM_PATH, useValue: 'RecodingDataEntryFormState.recording' }
]
})
export class RecordingDataEntryFormComponent extends BaseDataEntryFormComponent<
RecordingsListModel.RecordingModel,
RecordingDetailModel.RecordingModel> {
form: FormGroup;
@ViewChild('subject_id') subjectIdAutoComplete!: MatAutocompleteTrigger;
public autoCompletes;
id: number | undefined;
@Select(RecodingDataEntryFormState.getApiData) apiData$!: Observable<any>;
constructor() {
const form = new FormGroup({
name: new FormControl({}, [Validators.required]),
quality_comment: new FormControl({}),
subject_id: new FormControl({}, [Validators.required]),
recording_session_id: new FormControl({}, [Validators.required])
});
super(form);
this.form = form;
this.autoCompletes = this.subjectIdAutoComplete;
}
My app.module:
//...
declarations: [AppComponent, BaseDataEntryFormComponent],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: FakeBackend, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: HttpCredentialsInterceptor, multi: true },
{ provide: 'SnotifyToastConfig', useValue: notificationConfig },
{ provide: LOCALE_ID, useValue: 'de-DE' },
SnotifyService
],
bootstrap: [AppComponent]
//...
export class AppModule {
constructor(private injector: Injector) {
ServiceLocator.injector = this.injector;
}
}
//...
And the base Component:
@Component({
selector: 'app-base-data-entry-form-component',
template: '',
styles: []
})
export class BaseDataEntryFormComponent<L extends DatatableData, D> {
public options: { [key: string]: any[] } = {};
id: number | undefined;
private readonly dataEntryService: DataEntryService;
private baseService: BaseService;
private store: Store;
private router: Router;
private baseDetailsPageService: BaseDetailsPageService<RecordingDetailModel.RecordingModel>;
private basePageService: BasePageService<L>;
private formPath: string;
private activeEndpoint: string = '';
@SelectSnapshot(RecodingDataEntryFormState.formState) formState!: 'edit' | 'create';
@SelectSnapshot(RecodingDataEntryFormState.dirty) isDirty!: boolean;
public constructor(protected form: FormGroup) {
this.baseService = ServiceLocator.injector.get(BaseService);
this.store = ServiceLocator.injector.get(Store);
this.router = ServiceLocator.injector.get(Router);
this.baseDetailsPageService = ServiceLocator.injector.get(RecordingDetailsService);
this.basePageService = ServiceLocator.injector.get<BasePageService<L>>(ENTITYLISTSERVICE_PROVIDER);
this.formPath = ServiceLocator.injector.get<string>(ENTITY_FORM_PATH);
this.activeEndpoint = ServiceLocator.injector.get<string>(ENTITYENDPOINT_PROVIDER);
const formState = this.dataEntryService.getFormState();
this.store.dispatch(new RecordingFormActions.UpdateFormState(formState));
this.makeApiCall(this.dataEntryService);
I think that because the RecordingDataEntryFormComponent extends the BaseDataEntryFormComponent, the BaseDataEntryFormComponent should have the same providers, but it doesn't seem so.
Any help is very appreciated
Upvotes: 1
Views: 626
Reputation: 376
I solved it by not using my ServiceLocator anymore and instead inject the "Injector" locally at the RecordingDataEntryFormComponent and then passed it to the BaseDataEntryFormComponent.
Upvotes: 0
Reputation: 10979
You can pass the instance of the token from RecordingDataEntryFormComponent to BaseDataEntryFormComponent while calling super. Plus BaseDataEntryFormComponent shouldn't be a component. It should be a normal class. A component shouldn't extend another component as it won't serve a benefit. you can put @Directive() on it to use @Input @Output type decorators.
Upvotes: 1