In this post, we are going to go over the concept of Functional Reactive Programming from the point of view of an Angular 2 developer. Most of this is applicable for Angular 1 applications, but the examples in this post are in Angular 2. Let's go over the following topics:
  • A new asynchronous programming concept: the stream
  • A new primitive type: Observables
  • Functional Reactive Programming and RxJs
  • The essential of how Observables work
  • Commonly used operators: map, filter, reduce, scan
  • Common uses of RxJs in Angular 2: Forms and Http
  • The share operator and Hot vs Cold Observables
  • How to approach the learning of RxJs
  • Conclusions

Functional Programming in the Frontend World

Even though Functional Programming (FP) has been around for many years, the adoption has been slow in mainstream development. Some of its best practices are today more or less consensual, but for example only recently we started to see libraries capable of true function composition, like the latest lodash with first class FP support, or Ramda.

Frontend programming is inherently asynchronous, and there has always been something missing to allow the building of frontends in a functional-like way.

A New Asynchronous Programming Concept - The Stream

The notion that is missing and which is the heart of Functional Reactive Programing might very well be the stream. A stream is a sequence of values in time, as simple as that. Take for example the following stream of numeric values, where each value is issued every one second:

0, 1, 2, 3 ,4 

Another example of a stream is a sequence of mouse click events, with the x and y mouse coordinates of the mouse click:

(100,200), (110, 300), (400, 50) ...

Everything that happens in the browser can be seen as a stream: the sequence of browser events that are triggered when the user interacts with the page, data arriving from the server, timeouts getting triggered.

Streams seem to be a good model to describe how a frontend program actually works. But, is it possible to comfortably build a readable program around that notion?

A New Asynchronous Development Primitive - The Observable

In order for the notion of stream to be useful to build a program, we need a way to create streams, subscribe to them, react to new values, and combine streams together to build new ones.

Also, notice the similarity of the numeric stream above to something more familiar:

[0, 1, 2, 3, 4]

It looks a lot like a plain Javascript Array!

Arrays are data structures that are really easy to manipulate and combine to produce new arrays, thanks to its extended API. Look at all those data manipulation methods, and imagine that streams could be combined using these and many other functional programming operators.

This combination of a stream with a set of functional operators to transform streams leads us to the notion of Observable. Think of it as your API for tapping into a stream. You can use it to define a stream, subscribe to it, and transform it.

What we need at this point is a library that implements the Observable primitive, and thats where RxJs comes in.

Introducing RxJs

RxJs stands for Reactive Extensions for Javascript, and it's an implementation of Observables for Javascript. If Observables make it into ES7, you could see RxJs more or less as a pollyfill.

To see it in action, here is the same numeric stream we mentioned above, defined using RxJs:

var obs = Rx.Observable.interval(1000).take(5);

Now that we have the notions of Stream and Observable, we are now ready to introduce the notion of Functional Reactive Programming.

Introducing Functional Reactive Programming

Functional Reactive Programming (FRP) is a paradigm for software development that says that entire programs can be built uniquely around the notion of streams. Not only frontend programs, but any program in general.

While developing in this paradigm, development consists of creating or identifying the streams of values your program is interested in, combining them together, and finally subscribing to those streams to produce a reaction to new values.

The Core Goal of FRP

The main idea of FRP is to build programs in a declarative only way, by defining what are the streams, how they are linked together, and what happens if a new stream value arrives over time.

Programs such as this can be built with very little to no application state variables, which are in general a source of errors. To make it clearer: the application does have state, but that state is typically stored on certain streams or in the DOM, not on the application code itself.

Stateless UIs, but Which Part?

This absence of state is meant mostly for smart components that have data services injected. Pure components can consume observables but might want to keep some internal state variables in practice, think for example an isOpen flag for a dropdown.

The Essential of How Observables Work

Let's go back to the simple numeric sequence Observable presented before, and add a side effect to it:

var obs = Rx.Observable.interval(500)
           .take(5)
           .do(i => console.log(i) );

Note that you probably want to avoid the do() operator as its only purpose is to produce side effects.

If we run this program, you might be surprised by the fact that nothing gets printed to the console! This is because of one of the main properties of this type of Observable.

Observables are Either Hot or Cold

If this plain Observable has no subscribers, it will not be triggered!

The observable is said to be cold because it does not generate new values if no subscriptions exist. To get the numeric values printed to the console, we need to subscribe to the Observable:

obs.subscribe();

With this we do get the numeric values printed to the console. But, what happens if we add two subscribers to this observable:

var obs = Rx.Observable.interval(500).take(5)
            .do(i => console.log("obs value "+ i) );

obs.subscribe(value => console.log("observer 1 received " + value));

obs.subscribe(value => console.log("observer 2 received " + value));

What's happening here is that the Observable named obs has a side-effect: its prints to the console via the do() operator. Then two subscribers are added to obs, each one printing the result value to the console as well. This is the output of the console:

obs value 0
observer 1 received 0
obs value 0
observer 2 received 0

obs value 1
observer 1 received 1
obs value 1
observer 2 received 1

Looks like the side effect is being called twice! This leads to a second important property of Observables.

When we create a subscriber, we are setting up a whole new separate processing chain. The obs variable is just a definition, a blueprint of how a functional processing chain of operators should be set up from the source of the event up until the sink of the event, when that sink (the observer) is attached.

Being obs just a blueprint of how to build an operation chain, what happens when we subscribe two observers is that two separate processing chains are set up, causing the side effect to be printed twice, once for each chain.

There are ways to define other types of Observables where the side-effect would only be called once (see further). The important thing is to realize that we should keep two things in mind at all times when dealing with observables:

  • is the observable hot or cold?
  • is the observable shared or not?

Commonly Used RxJs Operators in Angular 2

There are many functional operators that can be used to combine Observables, so let's focus here on some of the most commonly used ones and how they can be used in an Angular 2 application.

Namely, we are going to see how some of those operators can be used in common tasks like form validation.

How Does Angular 2 Use Observables

Angular 2 currently uses RxJs Observables in two different ways:

  • as an internal implementation mechanism, to implement some of its core logic like EventEmitter
  • as part of its public API, namely in Forms and the HTTP module

The Map Operator

The map operator is probably the most well-known functional programming operator out there, and Observable of course provides it. The map operator simply takes an Observable and adds a transforming function that processes the output of the stream. For example:

var obs = Rx.Observable.interval(500).take(5)
            .map(i => 2 * i );

It's important to realize that the output of map is still another observable. What we have here is still only a definition of an operation chain. We still need to subscribe to this observable to get an output out of it.

Map and Filter Used to Do Form Validation

Another commonly used operator is filter. In Angular 2, forms can be handled as observables that we subscribe to. Meaning that the value of the whole form is itself an observable, and that the value of each individual field is itself an observable. Let's take for example a simple form:

<form [ngFormModel]="form" (ngSubmit)="onSubmit()">
   <p>
        <label>First Name:</label>
        <input type="text" ngControl="firstName">
   </p>
</form>

The use of NgFormModel allows to bind the form to a variable of type
ControlGroup in the component controller. There we can use that variable to access the form observable via form.valueChanges.

Using the observable, we can combine the map and filter operations to get an uppercase and validated version of the form content:

this.form.valueChanges
        .map((value) => {
            value.firstName = value.firstName.toUpperCase();
            return value;
        })
        .filter((value) => this.form.valid)
        .subscribe(validValue => ...);

See this post for further details on how to use NgFormModel to do this.

The Reduce Operator, and Why You Probably Don't Need It

There has been some talk recently on the Flux architecture, and how to use it to build Angular 2 applications, check for example this previous post. The main idea is to have a single atom of state for the whole application, subscribe to it, and create new values of it using reducer functions.

Crucial to that way of building frontends is the reduce functional operator, which is at the heart of Redux. RxJs observables also provide a reduce operator, so let's see how that looks:

var obs = Rx.Observable.interval(500).take(5);

var reduced = obs.reduce((state, value) => state + value , 0);

reduced.subscribe(total => console.log("total =" + total));

What is happening here is that given the obs observable, we create a second observable named reduced. Reduce emits a value when the stream obs closes and whose single value is the total sum of all elements in the stream. The output in the console is this:

total = 10

So, reduce emits the end total of the accumulation, which is true to the functional definition of the operator. But, this is not be what we want in the case that observable contained the application state instead of a numeric value.

The Scan Operator

You might be interested in the intermediate values of the reduce process, and might want to know what is the state of the observable after each element is reduced and react to that instead of only to the final result of the reduction operation. Especially because the reduced stream might never close!

This is what the scan operator does, and it's at the heart of how we can build Redux-like applications using RxJs:

var obs = Rx.Observable.interval(500).take(5);

var scanObs = obs.scan((state, value) => state + value , 0);

scanObs.subscribe(total => console.log(total));

Again, we created a second observable based on obs, and have subscribed to it. The result is:

0
1
3
6
10

We can see in the console the intermediate results of the accumulation process, and not only the final result.

One important property we saw at the beginning of this post, is that when we subscribe to an observable, it triggers the instantiation of a separate processing chain. The share operator allows to share a single subscription of a processing chain with other subscribers. Take for example the following:

var obs = Rx.Observable.interval(500).take(5)
            .do(i => console.log("obs value "+ i) )
            .share();

obs.subscribe(value => console.log("observer 1 received " + value));

obs.subscribe(value => console.log("observer 2 received " + value));

This creates the following output:

obs value 0
observer 1 received 0
observer 2 received 0

obs value 1
observer 1 received 1
observer 2 received 1

We can see the side effect inside the do call is only printed once instead of twice.

All Together Now

Its possible to implement a Flux-like Angular 2 application with a single atom of state in every way similar to Redux, by simply combining a couple of RxJs operators presented here. This is the subject of an upcoming post.

Conclusions

RxJS and FRP are really powerful concepts that are exposed in certain parts of the Angular 2 API, and that can be used to structure applications to be built in a very different way than before.

There are multiple choices available to structure Angular 2 applications. One option is to go full reactive in which case you will do extensive use of RxJs, but another option is to keep it simpler and use RxJs only via the parts of Angular that expose it in its public API (for example, Forms and HTTP).

You can also mix and match: use a reactive approach in parts of the application where a Flux architecture is beneficial (see here for when to use it), and a more traditional aproach elsewhere.

In both cases, and when building Angular 2 apps in general, it's important to gain some familiarity with RxJs.

How to Approach the Learning of RxJs

It's sometimes mentioned that RxJs has the potential for a large learning curve. This can likely be approached gradually, by focusing first on the couple of main core concepts: Observable laziness and hot vs. cold observables.

Then, it's a matter of focusing on the most commonly used RxJs operators, there are probably around 10 to 15 operators that are sufficient to build most programs.

One way to do it is to try RxJs using JsBin, trying one concept / operator at a time and take it from there.

References

Managing State in Angular 2 Applications by Victor Savkin (@victorsavkin)

The introduction to Reactive Programming you've been missing by Andre Staltz (@andrestaltz)

RxJs lessons on egghead.io