BACK

Events in Angular2

3 min read

During the feed component migration, I encountered code I did not know how to port to Angular 2:

if (!feed.isLocalScreen) {
// Until this timeout is reached, the "you are muted" notification
// will not be displayed again
var mutedWarningTimeout = now();
scope.$on("muted.byRequest", function () {
mutedWarningTimeout = secondsFromNow(3);
MuteNotifier.muted();
});
scope.$on("muted.byUser", function () {
// Reset the warning timeout
mutedWarningTimeout = now();
});
scope.$on("muted.Join", function () {
mutedWarningTimeout = now();
MuteNotifier.joinedMuted();
});
scope.$watch("vm.feed.isVoiceDetected()", function (newVal) {
// Display warning only if muted (check for false, undefined means
// still connecting) and the timeout has been reached
if (
newVal &&
feed.getAudioEnabled() === false &&
now() > mutedWarningTimeout
) {
MuteNotifier.speaking();
mutedWarningTimeout = secondsFromNow(60);
}
});
}

When the condition is true, the directive listens for muted.byRequest, muted.byUser, and muted.Join events. The event-handling code is straightforward (ignoring $watch for now).

But, wait a minute, I have read the documentation of Angular 2 like a hundred times and I don't remember nothing about "events" with Angular 1.X style. That's because it not exist. Angular 2 don't have a way to make events like in Angular 1, so I have to find a solution. After a search for a solution, I found this entry in laco's blog.

Broadcaster

Basically, the idea is to make a service that implements the $broadcast and $on a method as we had in $rootScope. To do this we use Observables, very importants in Angular 2, and for this case, we use a Subject.

import { Subject } from "rxjs/Subject";
import { Observable } from "rxjs/Observable";
import "rxjs/add/operator/filter";
import "rxjs/add/operator/map";
interface BroadcastEvent {
key: any;
data?: any;
}
export class Broadcaster {
private _eventBus: Subject<BroadcastEvent>;
constructor() {
this._eventBus = new Subject<BroadcastEvent>();
}
broadcast(key: any, data?: any) {
this._eventBus.next({ key, data });
}
on<T>(key: any): Observable<T> {
return this._eventBus
.asObservable()
.filter((event) => event.key === key)
.map((event) => <T>event.data);
}
}

So, now we can start to use events like in the example:

// child.ts
@Component({
selector: 'child'
})
export class ChildComponent {
constructor(private broadcaster: Broadcaster) {
}
registerStringBroadcast() {
this.broadcaster.on<string>('MyEvent')
.subscribe(message => {
...
});
}
emitStringBroadcast() {
this.broadcaster.broadcast('MyEvent', 'some message');
}
}

How I solved the problem?

I didn't. These events are only to show the user information pop-ups about when he is muted, so it's not a critical feature. By now these events are fired and listen in different components, and some of it still implemented in Angular 1.4.

This is a solution I want to share with you, but I'm not sure if this will be the way that I will use to solve the problem. Because these events probably won't be necessary when I reimplement the MuteNotifier.