samedi 25 juin 2022

Reuse and extend Angular component logic and template in child component

I have a form that is used to choose customer details. It is used in more than one places in my app but with extended logic and UI. I would like to be able to reuse my basic component in other components but also to extend(or override) it's template and logic. To don't have to copy paste the same UI & logic in each component and have one common basic place for changes.

base component with template & logic:

@Component({
selector: 'app-base',
template: `<h1> Base component </h1>
           <label>getLabel() </label>
           <ng-content> </ng-content> `
})

export class BaseComponent implements OnInit {

constructor() {
    // base init        
}

ngOnInit(): void {
    // base ngOnInit
}

getLabel(): string {
    return "label";
    }
}

Parent component that is suppose to reuse template, being able to extend methods and lifehooks and extend the UI as well.

@Component({
selector: 'app-parent',
template: `<app-base> <h1> extended </h1> </app-base>`, 
   })

export class ParentComponent extends BaseComponent {

constructor() {
    super();    
}

ngOnInit(): void {
    super.ngOnInit();
    // extended fancy stuff        
}

getLabel(): string {
    let a = super.getLabel();
    return a + "a"; // extended logic       
       }
}

It sort of works using this approach but one problem that I noticed is that the ngOnInit is called twice. Once from the base component since I'm using its template in parent component and second time because of parentComponent ngOnInit being triggered.

Question: Is there a way to reuse the template like using <app-base></app-base> with all shared logic in one place but without actually executing the lifehooks twice from both components?

Solution(?): The only thing that I came up is to wrap the basic component logic with a service. So there will be something like this:

@Component({
selector: 'app-base',
template: `<h1> Base component </h1>
           <label>getLabel() </label>
           <ng-content> </ng-content> `})
export class BaseComponent implements OnInit {

constructor(IBasicService basicService) { // <-- injected service
    // base init        
}

ngOnInit(): void {
    this.basicService.onInit(); // <-- using ngOnInit from service
    // base ngOnInit
}

getLabel(): string {
    return this.basicService.getLabel(); <-- using getLabel from service
     }
}

With this approach I'll be able to simply reuse my base component but with different injected services that will implement IBasicService interface and also simply extend the UI using or but is this correct way? Isn't there any better solution?

Thanks in advance!

Aucun commentaire:

Enregistrer un commentaire