Inheritance Visual
Oct 30 2018 03:20pm | | Share

Inheritance in Angular Components

By Shane Whittaker

Recently I worked on a project that needed two distinct layouts based on the browser width. Due to these components being purely presentational it was simple to use an approach that would just swap out the templates as the viewport changed/resized. This approach involves using component inheritance, with the help of class inheritance that is built into TypeScript. Inheritance is an object-oriented fundamental that allows us to derive properties and functions from a base class.

 

This post will show how to create two presentation components that will simply display some user information either using a list of cards or a table format using Angular Component inheritance.

 

The Base Component

First, we will define our base class. This class contains all the functionality that both components will share.

 

import { Injectable, Input, Output, EventEmitter } from '@angular/core';
import { User } from './user.service';

@Injectable()
export abstract class MyBaseComponent {
  public name: string;
 
  @Input() users: User[];
  @Output() onUserSelected: EventEmitter<User> = new EventEmitter();

  selectUser(user: User): void {
    this.onUserSelected.emit(user);
  }

 

Note that the class is using the Injectable decorator instead of the typical Component decorator.

 

Using Component Inheritance

The two components will simply inherit (or extend) the base class (MyBaseComponent). All of the properties, inputs, outputs and services of the base class will automatically be inherited, meaning that there is no need to duplicate these declarations in each extended component, but the public properties can be overridden. Below find both inherited components

 

Table Component

import { Component, forwardRef } from '@angular/core';

import { MyBaseComponent } from '../my-base.component';
 
@Component({

  selector: 'my-table',
  template: `<div class="table-responsive">
    <table class="table table-striped table-hover table-bordered">
      <thead>
        <tr>
          <th>User ID</th>
          <th>First Name</th>
          <th>Last Name</th>
          <th>Email</th>
          <th></th>
        </tr>
      </thead>
        <tbody>
          <tr *ngFor="let user of users">
            <td>{{user.id}}</td>
            <td>{{user.firstName}}</td>
            <td>{{user.lastName}}</td>
            <td>{{user.email}}</td>
            <td><button class="btn btn-success" (click)="selectUser(user)">Select</button></td>
          </tr>
        </tbody>
    </table>
  </div>`,
  providers: [{provide: MyBaseComponent, useExisting: forwardRef(() => MyTableComponent)}]
})
 
export class MyTableComponent extends MyBaseComponent {
  public name: string = "Table Component";
}

 

Card Component

 

import { Component, forwardRef } from '@angular/core';

import { MyBaseComponent } from '../my-base.component';
 
@Component({

  selector: 'my-cards',
  template: `<div class="panel panel-default" *ngFor="let user of users">
    <div class="panel-body">
      <div>
        <strong>User ID</strong> {{user.id}}
      </div>
      <div>
        <strong>First Name:</strong> {{user.firstName}}
      </div>
      <div>
        <strong>Last Name:</strong> {{user.lastName}}
      </div>
      <div>
       <strong>Email:</strong> {{user.email}}  
      </div>
      <div><button class="btn btn-success" (click)="selectUser(user)">Select</button></div>
    </div>
  </div>`,
  providers: [{provide: MyBaseComponent, useExisting: forwardRef(() => MyCardsComponent)}]
})
export class MyCardsComponent extends MyBaseComponent {
  public name: string = "Cards Component";
}

 

From these two subclasses, it’s easy to see how we could create more subclasses that inherent from the superclass (base component) to extend other common functionality. Now we can tie it all together and call these templates:

 


<my-table *ngIf="currentTab === 'table'" [users]="users" (onUserSelected)="setSelectedUser($event)"></my-table>

<my-cards *ngIf="currentTab === 'cards'" [users]="users" (onUserSelected)="setSelectedUser($event)"></my-cards>

 

 

For the complete code see here: https://stackblitz.com/edit/angular-jxbbaq