Replacement for missing Events class for Ionic 5

If you need a replacement for the missing Events service in Ionic, use this.

Problem

In older Ionic versions, you could use the Events class to publish and subscribe to events from different components. This is now gone. Some people will tell you that you shouldn't do this, instead rather keeping your model up-to-date and share that model. That is not always what you want though. For example, sometimes you want to mess around with that model and do something different with the result, or maybe call a completely unrelated component to do some sort of fetch/update/whatever.

Solution

1) Make a singleton service called something like EventsService.

import {Injectable} from '@angular/core';
import {Subject, Subscription} from 'rxjs';


@Injectable({
    providedIn: 'root'
})
export class EventsService {

    private channels: { [key: string]: Subject<any>; } = {};

    /**
     * Subscribe to a topic and provide a single handler/observer.
     * @param topic The name of the topic to subscribe to.
     * @param observer The observer or callback function to listen when changes are published.
     *
     * @returns Subscription from which you can unsubscribe to release memory resources and to prevent memory leak.
     */
    subscribe(topic: string, observer: (_: any) => void): Subscription {
        if (!this.channels[topic]) {
            this.channels[topic] = new Subject<any>();
        }

        return this.channels[topic].subscribe(observer);
    }

    /**
     * Publish some data to the subscribers of the given topic.
     * @param topic The name of the topic to emit data to.
     * @param data data in any format to pass on.
     */
    publish(topic: string, data?: any): void {
        const subject = this.channels[topic];
        if (!subject) {
            // Or you can create a new subject for future subscribers
            return;
        }

        subject.next(data);
    }

    /**
     * When you are sure that you are done with the topic and the subscribers no longer needs to listen to a particular topic, you can
     * destroy the observable of the topic using this method.
     * @param topic The name of the topic to destroy.
     */
    unsubscribe(topic: string): null {
        const subject = this.channels[topic];
        if (!subject) {
            return;
        }

        subject.complete();
        delete this.channels[topic];
    }
}

2) Make sure you then import it in your app.module.ts (or inject into your lazy loaded modules):

@NgModule({
  declarations: [
    ... blah blah
  ],
  entryComponents: [
    ... your pages here
  ],
  imports: [
    FormsModule,
    BrowserModule, 
    HttpClientModule,
    IonicModule.forRoot(), 
    RouterModule.forRoot(routes)
  ],
  providers: [
    ...
    EventsService,
    ...
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Note: I don't use lazy loading because I find it's a pain and makes everything more unnecessarily complicated for practically zero benefit. Your mileage may vary. I just want my app code to be simple and easy to maintain.

Conclusion

Now you can just 'Subscribe' and 'Publish' events as you did previously, done.

Hope this helps,

D

Comments: