Ionic 3 Component Inheritance

See: https://robferguson.org/blog/2018/09/28/ionic-3-component-inheritance/

TypeScript enables us to extend existing classes (in order to create new ones) and Angular includes support for component inheritance.

In order to minimise code duplication we can move common code into a base class.

For example:

import { Injector, OnInit, OnDestroy, Type } from '@angular/core';

import { Loading, LoadingController } from 'ionic-angular';

import { Subscription } from 'rxjs/Subscription';

import { LoggerService, StaticInjectorService } from '@app/core';

export abstract class CollectionPage implements OnInit, OnDestroy {

  protected loading = (() => {

    let loadMessage: Loading;

    return {

      present: () => {

        if (!loadMessage) {
          loadMessage = this.loadingCtrl.create({
            spinner: 'bubbles'
          });
        }

        loadMessage.present();

      },

      dismiss: () => {

        if (loadMessage) {
          loadMessage.dismiss().then(() => {
            loadMessage = null;
          });
        }

      }

    };

  })();
  
  protected loadingCtrl: LoadingController;
  protected logger: LoggerService;
  protected subscription: Subscription;
  
  constructor() {

    const injector: Injector = StaticInjectorService.getInjector();
    this.loadingCtrl = injector.get<LoadingController>(LoadingController as Type<LoadingController>);
    this.logger = injector.get<LoggerService>(LoggerService as Type<LoggerService>);
  }

  public ngOnInit() {
    this.subscribe();
  }

  protected subscribe() {
  }

  protected unsubscribe() {
    
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }

  public ngOnDestroy() {
    this.unsubscribe();
  }

}

A derived class:

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

import { IonicPage, NavController, NavParams } from 'ionic-angular';

import { EventsService } from '@app/core';
import { Event } from '@core/models';

import { CollectionPage } from '@pages/abstract/collection.page';

@IonicPage({
  name: 'EventsPage',
  segment: 'events',
  defaultHistory: ['TabsPage']
})
@Component({
  selector: 'page-events',
  templateUrl: './events.page.html'
})
export class EventsPage extends CollectionPage {

  public items: Array<Event>;
  
  constructor(public navCtrl: NavController,
              public navParams: NavParams,
              private eventsService: EventsService) {

    super();
  }
  
  protected subscribe() {

    this.loading.present();

    this.subscription = this.eventsService.list().subscribe(data => {
      
      this.items = data;
      this.loading.dismiss();
    });

  }  
  
}  

Notice the super() call in the derived classes constructor, because the base class uses static injection we don’t need to pass any constructor arguments.

Cool, happy to hear that someone is using abstract classes too :slight_smile:

Regarding injector I think there is also another way to achieve it. At least is what I do in my app, a bit more lines of code spared :wink:

 export abstract class AbstractPage {
     constructor(protected myService: MyService) {
     }
 }
 
 export class ChildClass {
    constructor(protected myService: MyService) {
         super(myService);
     }
 }