WebCake

When my Ionic 2 app went into beta, I learned a lot about app usage that I think I might have taken for granted over the years. One of the biggest facepalm moments came when one user told me that when she opened the app every morning, it would always show yesterday’s data and not a refreshed view.

As I’ve mentioned before, the app in question helps users track their daily diet intake along pre-set categories with user-adjustable targets. The intake page programmatically refreshes to the latest date as part of the onPageDidEnter hook, so it was a bit of a surprise to hear that it wasn’t refreshing.

And then of course, it occurred to me that the app wasn’t actually navigating, as one would expect when switching between pages. It was simply minimizing. When applied to the analogy of web applications – as Ionic apps are little more than that – it’s the same as minimizing your browser. You don’t leave the page, you just hide it from view.

The following code and examples are based on the Ionic 2.0.0-beta.6 release.

The Platform pause and resume Events

Whenever your Ionic 2 app gets sent to the background, usually from the user going back to the Home screen of their phone, or clicking a link that opens another application, the Platform will fire its pause event.

I’ll go into the details in a minute, but you can track that by adding a DOM listener to handle that event:

constructor() {
    document.addEventListener('pause', () => {
        this.someMethod();
    });
}

Similarly, you can do the same with the resume event:

constructor() {
    document.addEventListener('resume', () => {
        this.someMethod();
    });
}

In the examples above, I’m simply adding an event listener to my page’s constructor method, which tracks events on the DOM. In turn, it’ll fire off public or private methods within said page’s class.

You might be wondering why that works, and why we’re not handling it using some event handler that you would expect to be part of the Platform class, as you would have seen in an Ionic 1 app with $ionicPlatform.on('resume', function() {}). For that, let’s open up the source code.

Exploring the Platform class

At the time of this writing, you can access the source code of the Platform class by navigating to node_modules/ionic-angular/platform/platform.js. The very first thing you’ll notice is that Ionic pulls in the entire angular2/core namespace as core_1, which then gives it access to all of the classes therein.

On line 35, you’ll see the following block:

// Events meant to be triggered by the engine
// **********************************************
/**
* @private
*/
this.backButton = new core_1.EventEmitter();
/**
* @private
*/
this.pause = new core_1.EventEmitter();
/**
* @private
*/
this.resume = new core_1.EventEmitter();

Reading into it a bit, each of these events is a new instance of the EventEmitter class in Angular 2’s core namespace. You can read all about that in the Angular 2 docs.

You might have worked with the EventEmitter class before. I’ve even written a blog post about using it to build out a ticker component in Ionic 2. Though the block above might look different from other implementations, they’re all JavaScript, so they all do the same thing.

Event propagation in Angular 2

The Angular 2 docs make a big deal about being more focused on core DOM interaction than scoping everything to the Angular framework, as they did in version 1.x. This means that just about all of the interactions that we see are more inline with how JavaScript would normally behave, rather than how a massive framework might rewrite or privately scope functionality to fit its needs.

The result is that EventEmitter instances are really just document events – like a click, focus, etc. It’s captured at the DOM level at which it’s triggered, and ultimately propagates up until it hits the document.

Multiple handlers

You might find that you need to set multiple handlers on multiple pages. In doing some light experiments, I’ve been able to fire events both on the active component, as well as in its parent class. For example, I might add a listener on a Page within the tab navigation, and then add another independent listener to the Tabs constructor as well.

In those cases, you might consider how things are stored in the DOM, vs. how they’re removed from the DOM when navigating. For example, if you’re working in the Tabs view, you might find that some of your resume event handlers aren’t being fired if your tab in question isn’t active. Keep in mind, that’s because it’s been removed from the DOM, and replaced with a new array of pages. I talk about that a lot in a post about exploring the NavController. In cases like those, you might want to make sure that whatever event handler you expect to be fired might also be fired in the page lifecycle hooks.

Feel free to let me know what you think in the comments below. Happy to go into more detail, or answer any questions based on what I’ve seen.

Leave a Reply