Can't resolve all parameters for [Component]

南笙酒味 提交于 2019-12-11 02:35:49

问题


In my generic component I have this squiggly saying: 'Angular: Can't resolve all parameters for BaseCollectionComponent' in [path/base-collection.component.ts: ([object.Object], [object.Object], ?, [object.Object])]'

Here is the code of the component:

import {BaseRepositoryService} from '../../services/base-repository.service';
import {Component, ComponentRef, Type, ViewChild, ViewContainerRef} from '@angular/core';
import {BaseComponent} from '../base-component/base.component';
import {CreateCollectionItemModel} from '../../models/create-collection-item.model';
import {ComponentFactoryService} from '../../services/component-factory.service';
import {FrontendSelectorsIds} from '../../globals/frontend-selectors-ids';
import {BaseCollectionItemComponent} from '../base-collection-item/base-collection-item.component';

@Component({
  selector: FrontendSelectorsIds.BaseCollectionSelector,
  templateUrl: './base-collection.component.html',
  styleUrls: ['./base-collection.component.less']
})
export class BaseCollectionComponent<TypeModel> {

  @ViewChild('collectionItemsContainer', {read: ViewContainerRef}) collectionItemsContainer: ViewContainerRef;
  model: TypeModel[];
  components: ComponentRef<BaseComponent<TypeModel>>[];

  constructor(public repository: BaseRepositoryService<TypeModel>,
              public factoryService: ComponentFactoryService<TypeModel, BaseComponent<TypeModel>>,
              public componentType: Type<BaseCollectionItemComponent<TypeModel>>,
              public createCollectionItemModel?: CreateCollectionItemModel) {
    this.components = [];
  }

  loadModel(): void {
    this.repository.getAll()
      .then(results => {
        this.model = results;
        this.onLoadModelComplete();
      });
  }

  destroyChildren(): void {
    if (this.components) {
      for (const component of this.components) {
        component.destroy();
      }
    }
  }

  onLoadModelComplete() {
    this.createComponents(this.model);
  }

  mapResultsToCollection(): void {

  }

  createComponents(model: TypeModel[]): void {
    this.factoryService.setRootViewContainerRef(this.collectionItemsContainer);

    for (const item of model) {
      const newComponent = this.factoryService.addDynamicComponentWithModel(item, this.componentType);
      this.components.push(newComponent);
    }
  }
}

Basically this component is made to inject the children list-items components for collections.

First thing I don't really get where the error is pointing me to, but I assume it points to the constructor since there are also 4 parameters. The question mark is pointing to the 3rd position and it is the type parameter that I provide in the child classes.

I have looked up existing problems of the same kind but non of the provided solutions worked for me.

The option to emit decorators metadata (toggle true/false) did't help.

Any suggestions? In case more code is needed, let me know. Thanks in advance!

UPDATE

The classes that are used as parameters (the way they are declared):

repository

@Injectable()
export class ProductRepositoryService extends BaseRepositoryService<Product>
@Injectable()
export abstract class BaseRepositoryService<TypeModel>

It is a service base for communication with my bnackend api. It has HttpClient in it injected by Angular. Nothing special.

factoryService

@Injectable()
export class ComponentFactoryService<TypeModel, TypeCollectionItem extends BaseCollectionItemComponent<TypeModel>>

This service takes care of spawning components.

componentType

export class ProductItemComponent extends BaseCollectionItemComponent<Product> implements OnInit

This is a basic component that I use to display list items of a collection.

createCollectionItemModel

export class CreateCollectionItemModel

This is just a class to contain data.

In my opinion this whole problem has something to do with the 3rd parameter, with that type I provide for the factory service. I think there is some kind of mismatch. I was wrestling with it to get it to work. The problem part was to generically pass the type of the desired component to instantiate. Here is the code that makes it all work (at least in the dev mode):

This is the BaseCollectionComponent class call (from the original post):

createComponents(model: TypeModel[]): void {
    this.factoryService.setRootViewContainerRef(this.collectionItemsContainer);

    for (const item of model) {
      const newComponent = this.factoryService.addDynamicComponentWithModel(item, this.componentType);
      this.components.push(newComponent);
    }
  }

Here is the factoryService full code:

@Injectable()
export class ComponentFactoryService<TypeModel, TypeCollectionItem extends BaseCollectionItemComponent<TypeModel>> {

  rootViewContainer: ViewContainerRef;

  constructor(@Inject(ComponentFactoryResolver) private _factoryResolver: ComponentFactoryResolver) {
  }

  setRootViewContainerRef(viewContainerRef: ViewContainerRef) {
    this.rootViewContainer = viewContainerRef;
  }

  addDynamicComponentWithModel(model: TypeModel, componentType: Type<TypeCollectionItem>): ComponentRef<TypeCollectionItem> {
    const factory = this._factoryResolver.resolveComponentFactory(componentType);
    const component = factory.create(this.rootViewContainer.parentInjector);

    this.rootViewContainer.insert(component.hostView);
    component.instance.model = model;

    return component;
  }
}

The way I made it work is looking like somewhat generics hell. I hope this will add up to understanding what's wrong here.


回答1:


It isn't an @Injectable, thus you can't make use of dependency injection.




回答2:


Well, it turns out that the 3rd argument to the BaseCollectionComponent constructor indeed caused the problem. I simply started to unplug one-by-one all the code bits and see if the problem disappears. After I have removed the Type<...<...>> parameter (thew 3rd one) and instead I changed this:

 createComponents(model: TypeModel[]): void {
    this.factoryService.setRootViewContainerRef(this.collectionItemsContainer);

    for (const item of model) {
      const newComponent = this.factoryService.addDynamicComponentWithModel(item, this.componentType);
      this.components.push(newComponent);
    }
  }

to this:

    createComponents(model: TypeModel[], type: any): void {
    this.factoryService.setRootViewContainerRef(this.collectionItemsContainer);

    for (const item of model) {
      const newComponent = this.factoryService.addDynamicComponentWithModel(item, type);
      this.components.push(newComponent);
    }
  }

the problem disappeared. Seems that passing a parameter 'of type of type of type' did confuse the angular compiler in some way. I still don't get why would it. If someone could point it out? Anyway, thanks for suggestions everyone.



来源:https://stackoverflow.com/questions/47617660/cant-resolve-all-parameters-for-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!