Friday, January 01, 2016

Angular2 Custom Events

Angular2 beta just came out and has events based on RxJS. Events are used in Inputs and Outputs and the docs show how to emit an event but not how to subscribe to them. You might need them for inter-service communication. There might be better options for that, but nowhere to find in the docs for now, the docs are being written at the moment.

The doc for EventEmitter is here:

https://angular.io/docs/ts/latest/api/core/EventEmitter-class.html

Digging in the code for EventEmitter

https://github.com/angular/angular/blob/2.0.0-beta.0/modules/angular2/src/facade/async.ts#L68-L164

allows to write some code like this in Typescript:

First, we need to import the EventEmitter class in each .ts file that uses events:

import {EventEmitter} from 'angular2/core';  

Then we can create an event emitter, a source, that we named ticktickevent:

asyncevent: boolean = true;  
ticktickevent: EventEmitter;

The only argument to EventEmitter(async: boolean) is a boolean specifying if the event needs to be treated synchronously, in that case the onNext, onError and onComplete callbacks are called right away, or asynchronously, meaning that the callbacks are put in the timeout queue and called after the UI events are completed. Use async = true if you are executing lengthy code in the callbacks, that leaves the priority to user events and should keep the UI responsive.

EventEmitter is a generic class, replace by the type of event that you want to emit. In our case, Object is used to keep things simple, since we emit events like this: {event: 'ticktick', data: 'fun'}. It would be best to declare a Typescript interface for the event, so Typescript can check that the proper object structure is used in all the calls. You could use EventEmitter or EventEmitter if your event is only a string or a number.

Then we subscribe to the event:

ticktickevent.subscribe(onNextEvent);  
 or  
ticktickevent.subscribe(onNextEvent, onErrorEvent);  
 or  
ticktickevent.subscribe(onNextEvent, onErrorEvent, onCompletedEvent);  

depending on your needs for all the callbacks or only some, The signature of the method is:

EventEmitter.subscribe(generatorOrNext?: any, error?: any, complete?: any) : any;  

The callbacks are like this:

onNextEvent(event) {  
   console.log("onNextEvent event: %o", event);  
  }  
 onErrorEvent(error) {  
   console.log("onErrorEvent error: %o", error);  
  }  
 onCompletedEvent() { // no param  
   console.log("onCompletedEvent");  
  }  

To generate a regular (not an error) event:

ticktickevent.next({'event': 'ticktick', 'data': 'fun'});

which will call

onNextEvent(event) with event = {'event': 'ticktick', 'data': 'fun'}

To trigger an error:

ticktickevent.error({'type': 'stream error', data: '42'});

which will call

onErrorEvent(error) with error = {'type': 'stream error', 'data': '42'}

and to complete (close) the event stream:

ticktickevent.complete();  

which in turn will call

onCompletedEvent();

with no argument.

That's it, you should be able to create an event emitter, emit events and subscribe to them.
You should be able to use that in Javascript as well, just drop all type indications in the code.

Sorry for the bad formatting, I'll fix it when I get some time.