Reactive functional programming in Angular 2

The Observable pattern stands at the core of what we know as reactive functional programming. Basically, the most basic implementation of a reactive functional script encompasses several concepts that we need to become familiar with:

  • An Observable
  • An Observer
  • A timeline
  • A stream of events featuring the same behavior as an objects collection
  • A set of composable operators, also known as Reactive Extensions

Sounds daunting? It's not. Believe us when we tell you that all of the code you have gone through so far is much more complex than this. The big challenge here is to change your mindset and learn to think in a reactive fashion, and that is the main goal of this section.

If we want to put it simply, we can just say that reactive programming entails applying asynchronous subscriptions and transformations to Observable streams of events. We can imagine your poker face now, so let's put together a more descriptive example.

Think about an interaction device such as a keyboard. A keyboard has keys that the user presses. Each one of those key strokes triggers a key press event. That key press event features a wide range of metadata, including—but not limited to—the numeric code of the specific key the user pressed at a given moment. As the user continues hitting keys, more keyUp events are triggered and piped through an imaginary timeline. Congratulations! You have an Observable sequence in the works here: the keyboard assumes the role of an Observable and emits a sequence of events that inform of the keys pressed no matter what happens next. Each keystroke event is agnostic from the rest and they follow a sequence along time. Now we mention events, one occurring after another. If we grab a group of elements of a given type (not necessarily the same type though) and wrap them in an object (which is what that timeline is), isn't it a collection? Moreover, that collection is spanned along time. So isn't that a stream? Indeed it is, so congratulations! You now have an event stream emitted by the Observable for your listening delight:

Reactive functional programming in Angular 2

Our stream of key press events is looking really good, but we are getting notifications for all the keys pressed. What if we want to subscribe to a subset of the stream that observes the events represented by cursor keys? We could be coding a simple game and those are the keys that control our avatar in the game, while other key events are completely useless for the purpose of the game. Our ideal stream should contain only cursor keys' events then. This is where the functional part of the reactive paradigm comes into play.

Let's imagine we are grabbing that event stream and filtering it to include only the key press events that pertain to interactions with the cursor keys, disregarding all the others. On top of that, we are going to throttle the stream to allow a key press event to pass through only every 500 milliseconds, so we do not overflow whatever is listening at the other end of the wire. Now we have a new event stream, which is the by-product of the previous one, but represents only a subset of the information with a very specific goal:

Reactive functional programming in Angular 2

If we subscribe to this last stream, we can take action on each cursor key press and apply some gamification logic to whatever game we are developing at this time. We can even hook up several subscribers to that stream, or apply further transformations using other Reactive Extensions to create brand new streams that other subscribers can subscribe to in order to perform other business or presentation logic not related whatsoever to that performed by the original subscriber.

This logic can be ported to the realm of components to handle interaction events, asynchronous behavior, or (as this chapter aims to describe) the consumption and digestion of information served by an API service or data store. In order to do so, Angular 2 relies on RxJS, whose core module is required as a peer dependency when installing Angular 2. The RxJS API provides all that we need to put the aforementioned things to work on our asynchronous operations with Angular 2.

The RxJS library

As mentioned previously, Angular 2 comes with a peer dependency on RxJS, the JavaScript flavor of the ReactiveX library that allows us to create Observables and Observable sequences out of a large variety of scenarios, such as interaction events, promises, or callback functions, just to name a few. In that sense, reactive programming does not aim to replace asynchronous patterns such as promises or callbacks. All the way around, it can leverage them as well to create Observable sequences.

RxJS comes with built-in support for a wide range of composable operators to transform, filter, and combine the resulting event streams. Its API provides convenient methods to subscribe Observers to these streams so that our scripts and components can respond accordingly to state changes or interaction inputs. While its API is so massive that covering it in detail is out of the scope of this book, we will highlight some bits of its most basic implementation in order for you to better understand how HTTP connections are handled by Angular 2.

Before jumping onto the HTTP API provided by Angular 2, let's create a simple example of an Observable event stream that we can transform with Reactive Extensions and subscribe observers to. To do so, let's pick the scenario described in the previous section.

We envisioned how a user interacting with our application through the keyboard can't turn into a timeline of keystrokes and, therefore, an event stream. Go back to JSBIN, delete the contents of the JavaScript pane, and then write down the following snippet:

var keyboardStream = Rx.Observable
  .fromEvent(document, 'keyup')
  .map(x => x.which);

The preceding code is pretty self-descriptive. We leverage the Rx.Observable class and its fromEvent method to create an event emitter that streams the keyup events that take place in the scope of the document object. Each of the event objects emitted is a complex object, so we simplify the streamed objects by mapping the event stream onto a new stream that contains only the key codes pertaining to each keystroke. The map method is a Reactive Extension that features the same behavior as the JavaScript map functional method. This is why we usually refer to this code style as reactive functional programming.

All right, so now we have an event stream of numeric keystrokes, but we are only interested in observing those events that inform of hits on the cursor keys. We can build a new stream out of an existing stream by applying more Reactive Extensions. So, let's do it with keyboardStream by filtering such a stream and returning only those events that are related to cursor keys. We will also map those events to their text correspondence for the sake of clarity. Append the following chunk of code right below the previous snippet:

var cursorMovesStream = keyboardStream.filter(x => {
    return  x > 36 && x < 41;
  })
  .map(x => {
    var direction;
    switch(x) {
      case 37:
        direction = 'left';
        break;
      case 38:
        direction = 'up';
        break;
      case 39:
        direction = 'right';
        break;
      default:
        direction = 'down';
    }
    return direction; 
  });

We could have done all of this in a single action by chaining the filter and map methods to the keyboardStream Observable and then subscribing to its output, but it's generally a good idea to separate concerns. By shaping our code in this way, we have a generic keyboard events stream that we can reuse later on for something completely different. So, our application can scale up while keeping the code footprint to a minimum.

Now that we have mentioned subscribers, let's subscribe to our cursor moves stream and throw the move commands at the console. We type the following statement at the end of our script, then clear the Console pane, and click on the Output tab so that we can have a document available:

cursorMovesStream.subscribe(e => console.log(e));

Click anywhere on the Output pane to put the focus on it and start typing random keyboard keys and cursor keys:

The RxJS library

You are probably wondering how we can apply this pattern to an asynchronous scenario such as consuming information from a HTTP service. Basically, you have so far become used to submitting async requests to AJAX services and then delegating the response handling to a callback function or just piping it through a promise. Now, we will handle the call by returning an Observable. This Observable will emit the server response as an event in the context of a stream, which will be funneled through Reactive Extensions to better digest the response.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.207.164