Skip to content

Instantly share code, notes, and snippets.

@daleffe
Forked from sagrawal31/events.ts
Last active January 24, 2024 12:24
Show Gist options
  • Save daleffe/60ff599dfdb0feb7502cb5fa60573394 to your computer and use it in GitHub Desktop.
Save daleffe/60ff599dfdb0feb7502cb5fa60573394 to your computer and use it in GitHub Desktop.
Alternative to Events which got removed in Ionic 5+
import { Injectable } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
/**
* A custom Events service just like Ionic 3 Events https://ionicframework.com/docs/v3/api/util/Events/ which got removed in Ionic 5.
*
* @author Shashank Agrawal
* @author Guilherme Roberge Daleffe
*/
@Injectable({ providedIn: 'root' })
export class Events {
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]) {
/* - For Subject, we don't need to initial a value
* this.channels[topic] = new Subject<any>();
* - You can also use ReplaySubject (for future subscribers, this will always give you the last value)
* this.channels[topic] = new ReplaySubject<any>(1);
* - In BehaviorSubject, the subscribers will receive the previous value and also upcoming value
* this.channels[topic] = new BehaviorSubject<any[]>([]);
*/
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[]): boolean;
publish(topic: string, data: any): boolean;
publish(topic: string, data?: unknown): boolean {
const subject = this.channels[topic];
if (!subject) { return false; }
subject.next(data);
return true;
}
/**
* 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.
*/
destroy(topic: string): boolean {
const subject = this.channels[topic];
if (!subject) { return false; }
subject.complete();
delete this.channels[topic];
return true;
}
}
import { Injectable } from '@angular/core';
export type EventHandler = (...args: any[]) => any;
@Injectable({
providedIn: 'root',
})
export class Events {
private c = new Map<string, EventHandler[]>();
constructor() {
console.warn(`[DEPRECATION][Events]: The Events provider is deprecated and it will be removed in the next major release.
- Use "Observables" for a similar pub/sub architecture: https://angular.io/guide/observables
- Use "Redux" for advanced state management: https://ngrx.io`);
}
/**
* Subscribe to an event topic. Events that get posted to that topic will trigger the provided handler.
*
* @param topic the topic to subscribe to
* @param handler the event handler
*/
subscribe(topic: string, ...handlers: EventHandler[]) {
let topics = this.c.get(topic);
if (!topics) {
this.c.set(topic, topics = []);
}
topics.push(...handlers);
}
/**
* Unsubscribe from the given topic. Your handler will no longer receive events published to this topic.
*
* @param topic the topic to unsubscribe from
* @param handler the event handler
*
* @return true if a handler was removed
*/
unsubscribe(topic: string, handler?: EventHandler): boolean {
if (!handler) {
return this.c.delete(topic);
}
const topics = this.c.get(topic);
if (!topics) {
return false;
}
// We need to find and remove a specific handler
const index = topics.indexOf(handler);
if (index < 0) {
// Wasn't found, wasn't removed
return false;
}
topics.splice(index, 1);
if (topics.length === 0) {
this.c.delete(topic);
}
return true;
}
/**
* Publish an event to the given topic.
*
* @param topic the topic to publish to
* @param eventData the data to send as the event
*/
publish(topic: string, ...args: any[]): any[] | null {
const topics = this.c.get(topic);
if (!topics) {
return null;
}
return topics.map(handler => {
try {
return handler(...args);
} catch (e) {
console.error(e);
return null;
}
});
}
}

1. Change the imports

Before

import { Events } from 'ionic-angular';

After

import { Events } from '../your/path/to/service/events';

2. Changes in the subscribe method

Before

events.subscribe('user:created', (user, time) => {
    console.log('Welcome', user, 'at', time);
});

After

this.events.subscribe('user:created', (data: any) => {
    console.log('Welcome', data.user, 'at', data.time);
});

3. To publish (both methods accepted)

this.events.publish('user:created', someUserInstance, Date.now());
this.events.publish('foo:user:logged-out', {
    user: someUserInstance,
    time: new Date()
});

4. To Unsubscribe

const subscription = this.events.subscribe('user:foo:created', (data: any) => {
    // your logic
});

Once you are done, you can do this:

subscription.unsubscribe();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment