Search code examples
javascriptangulartypescriptangular6composition

How to use composition instead of inheritance when sharing logic between components in Angular 6?


I have a module in Angular that is structured likes this:

moduleName
    componentA
    componentB

Now componentA and componentB are very similar, as they share some attributes and methods, e.g.:

protected available: boolean = true;

As I don't want to repeat myself, I've created a base class, that stores all this:

export abstract class BaseComponent {
    protected available: boolean = true;
}

And both controllers inherit from that class:

import { BaseComponent } from '../base.component';

export class ComponentA extends BaseComponent implements OnInit {
    constructor() {
        super();
    }

    ngOnInit() {
        console.log(this.available);
    }
}

This works just fine. However, when I research this soultion a lot of people are saying:

Don't use inheritance, use composition in this case.

Alright, but how can I use composition instead? And is the gain really that big over the current solution?

Thanks a lot for your time.


Solution

  • For composing objects in angular you need to have a reference to that object inside of your class, which shares data and functionality. To do that you need to use Angular services, and inject them to your class, and there should be 1 instance of service per component.

    1. Create a new service by running ng g s my-service, remove providedIn: 'root' from your service annotation (We want to provide instance per component)
    2. Add public available: boolean = true; to the service
    3. provide the service through the components, in @Component configs on your components
    4. inject the service in your both component constructors, constructor(private myService:MyService)

    Now you have a composition that keeps data and functionality

    @Component({
      selector: 'app',
      templateUrl: './app.my-component.html',
      styleUrls: ['./app.my-component.css'],
      providers: [MyService]
    })
    export class MyComponent {
      constructor(private myService: MyService) {
      }
    }