Last update on Sunday, February 3rd 2019

Using Angular Custom Decorators in an Ionic application (Final Part)

In the previous tutorial, we learned how to create our own Angular Decorators.
Now that we have more experience, we can attack more complex cases.

In this tutorial, we will:

  1. Use the Ionic Hooks and Modal API to create an ExitModal Angular Decorator
  2. Compose it with the TimeTracker that we previously created to display how much time a user spent on a tab

The ExitModal Decorator

We are going to use the Ionic Modal API when the ionViewWillLeave hook will be triggered.
Using Angular's IOC in a Decorator is quite tricky since we are not in an Angular Class, we don't have a constructor to inject an Angular Service.

The Injector Service is a great solution to this issue. However, we need an instance to work with.

Let's make the following modifications to the app.module.ts file:

import { NgModule, Injector } from '@angular/core';
.
.
.
@NgModule({
  declarations: [AppComponent, ExitModalPage],
  entryComponents: [ExitModalPage],
  .
  .
  .
})
export class AppModule {
  static injector: Injector;

  constructor(private injector: Injector) {
    AppModule.injector = injector;
  }
}

We inject the Injector service and put an instance directly in the AppModule Component so we can use it in the following ExitModal Decorator:

import { ModalController } from '@ionic/angular';

import { AppModule } from '../../app.module';
import { ExitModalPage } from './exitModal.component';

export function ExitModal() {
  return function (constructor) {
    let modalController = AppModule.injector.get(ModalController)

    const ionViewWillLeaveHook = "ionViewWillLeave";
    const original = constructor.prototype[ionViewWillLeaveHook];

    constructor.prototype[ionViewWillLeaveHook] = function ( ...args ) {
      original && original.apply(this, args);

      showModal();
    }
  }
  .
  .
  .
}

In order to use the Ionic Modal API, we grab the AppModule and use its injector static property to get an instance of the modalController.

The modalController will then be used in a showModal method once the ionViewWillLeave will be triggered.
As you can see, we also imported an ExitModalPage Component. This Angular Component is quite simple, it will just display a "Good Bye" message when the user leaves.

Which is as follow:

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

@Component({
  selector: 'modal-page',
  template: '<h1 text-center>Good Bye</h1>'
})
export class ExitModalPage {
  constructor() {}

}

Back to the showModal method:

    async function showModal() {
      let modal = await modalController.create({
        component: ExitModalPage
      });

      return await modal.present();
    }

We have here a very simple use of the modalController's create method by just passing the ExitModalPage.
If you want more information on the Ionic Modal API, the documentation is available there.

We only need to use the ExitModal Decorator as a Class Decorator on the Tab1:

import { Component } from '@angular/core';
import { ExitModal } from '../decorators/exit-modal/ExitModal.decorator';

@Component({
  selector: 'app-tab1',
  templateUrl: 'tab1.page.html',
  styleUrls: ['tab1.page.scss']
})
@ExitModal()
export class Tab1Page {
  constructor() {}
}

And here is the result:

Ionic Angular Custom Ionic API Decorator Result

The ExitTimeTrackerModal Decorator

Let's push our newly acquired knowledge to the limit by composing two of our most complex Decorators into one.

In this part, we will create an exit modal that displays how much time a user spent on a tab: the ExitTimeTrackerModal.

This Decorator is not as scary as it looks like:

import { ExitModal } from './exitModal.decorator';
import { TimeTracker } from '../timeTracker.decorator';

export function ExitTimeTrackerModal(viewName) {
  return function (constructor) {
    ExitModal(viewName)(TimeTracker()(constructor));
  }
}

In fact, it could be changed as follow:

import { ExitModal } from './exitModal.decorator';
import { TimeTracker } from '../timeTracker.decorator';

export function ExitTimeTrackerModal(viewName) {
  return function (constructor) {
    var constructorThatHasTheTimeSpent = TimeTracker()(constructor)
    ExitModal(viewName)(constructorThatHasTheTimeSpent);
  }
}

We import the ExitModal and the TimeTracker Decorators.
A Decorator is a function that returns a function.
We can use the currying mechanism as long as we follow this sequence:

Decorator(arg1, arg2, etc)(constructor)

Hence, we start with the TimeTracker Decorator:

export function TimeTracker() {
  return function (constructor) {
    .
    .
    .
    constructor.prototype[ionViewWillLeaveHook] = function ( ...args ) {
      const endTime = new Date();
      constructor.timeSpent = endTime.getTime() - startTime.getTime();

      original2 && original2.apply(this, args);
    }
    return constructor;
  }
}

We keep the same behavior as before.
However, instead of logging the time spent, we stock it directly in the constructor that will be passed to the ExitModal Decorator.

export function ExitModal(viewName) {
  return function (constructor) {
    constructor.prototype[ionViewWillLeaveHook] = function ( ...args ) {
      original && original.apply(this, args);

      showModal(viewName, constructor.timeSpent);
    }

    async function showModal(viewName, timeSpent) {
      let modal = await modalController.create({
        component: ExitModalPage,
        componentProps: {
          timeSpent: timeSpent,
          viewName: viewName 
        }
      });

      return await modal.present();
    }
  }
}

Same as before, we use the create method, but this time we use the viewName value that we got from the ExitTimeTrackerModal and the timeSpent from the constructor that was modified by the previous ExitModal Decorator.

Finally, we have both Angular Decorators working together!

Ionic Angular Custom Ionic API Decorator Final Result

Conclusion

We have seen in this tutorial how to inject the Ionic Modal API in a custom Angular Decorator and how to combine two Decorators.
Decorators can be quite scary because they are relatively new in JavaScript.
At the end of the day, they are just functions that receive some parameters and a targeted constructor.
If you want to push it further, I invite you to check one of Victor Savkin's post on Decorators, HOC, metaprogramming and the Angular Ivy.

Using Angular Custom Decorators in an Ionic application (Part 1)

In this tutorial, we will see how to...

Action Range and spooky Sounds in an AR Ionic app with Wikitude

Learn how to use Wikitude's Action...

Adding Redux to an Ionic Application

Learn how to mix together your...

Stay up to date


Join over 4000 other developers who already receive my tutorials and their source code out of the oven with other free JavaScript courses and an Angular cheatsheet!
Designed by Jaqsdesign