Component Inheritance and DI for base class resolver

414 Views Asked by At

I have a different types of components but sharing some common algorithms. So I have decided to use Component Inheritance in Angular and tried with template method pattern.

Basically, I need to do a different implementation for some of the methods.

Base Component

@Injectable()
export abstract class ComponentBase<IComponentViewData> {    
    public isReadOnly: boolean;
    public data: any;
    public message: string;

    // template method
    saveData(){
        validateBeforeSave();
        save();
        afterSave();
    }
    save(){
    }
    protected abstract afterSave(){
    }
    protected abstract validateBeforeSave(): void;

    }
    exit(){

    }
}

Child Component - Type A

@Component({
    templateUrl: "app/component/childA.component.html",
    selector: "child-a"

})
export class ChildAComponent extends ComponentBase<IChildTypeAViewData> { //IChildTypeAViewData : IComponentViewData

    protected afterSave(){
      this.message ='Child A executed successfully'
    }

}

ChildA.component.html

It uses parent component fields and methods. Also embeds the common message templates that depends on parent component.

<div *ngIf="isReadOnly">
Show Data here
<button (click)="saveData()" />
<message></message>
</div>

MessageComponent embedded in ChildA.component

@Component({
    templateUrl: "app/common/message.html",
    selector: "message"

})
export class MessageComponent {

    constructor(@Host() hostComponent: ComponentBase<IComponentViewData>) {

    }
}

message.html

<div>{{ hostComponent.message }} </div>
<button (click)="exit()"></button>

Problem:

As I embed message component in any of the Child types say ChildA, ChildB I could not specify the proper derived class in Message component @Host. So dependency resolver provides an error No provider for ComponentBase.

I used @Host in order to access the contained parent component's methods. Most of them are in abstract component.

Do we need to use ComponentFactoryResolver? Or someother way we can try instead of Host?

1

There are 1 best solutions below

0
On

Edit ChildA.component.ts metadata with the following configuration:

@Component({
  templateUrl: "app/component/childA.component.html",
  selector: "child-a",
  providers: [
   { provide: ComponentBase, useExisting: forwardRef(() => ChildAComponent) }
  ]
})

The parent must cooperate by providing an alias to itself in the name of a class-interface token.

More info in the official docs.