Reputation: 141
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.
Upvotes: 2
Views: 4259
Reputation: 141
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.
Upvotes: 1
Reputation: 2831
It isn't an @Injectable, thus you can't make use of dependency injection.
Upvotes: 1