简体   繁体   English

Angular 提供程序在扩展组件中丢失

[英]Angular providers lost in extended Component

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.父组件具有从同一服务扩展的所有不同服务,我想将此服务传递给 Base 组件,以便它可以完成工作。

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.我认为因为 RecordingDataEntryFormComponent 扩展了 BaseDataEntryFormComponent,所以 BaseDataEntryFormComponent 应该具有相同的提供程序,但似乎并非如此。

Any help is very appreciated非常感谢任何帮助

You can pass the instance of the token from RecordingDataEntryFormComponent to BaseDataEntryFormComponent while calling super.您可以在调用 super 时将令牌实例从 RecordingDataEntryFormComponent 传递给 BaseDataEntryFormComponent。 Plus BaseDataEntryFormComponent shouldn't be a component.加上 BaseDataEntryFormComponent 不应该是一个组件。 It should be a normal class.它应该是一个普通的 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.您可以将 @Directive() 放在上面以使用 @Input @Output 类型的装饰器。

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.我通过不再使用我的 ServiceLocator 来解决它,而是在 RecordingDataEntryFormComponent 本地注入“Injector”,然后将其传递给 BaseDataEntryFormComponent。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM