Functional and reactive programming in Angular 2

Functional and reactive programming in Angular 2

  • 2016-09-15
  • 2256

Reactive programming with Angular 2 .In real applications, we have to deal with asynchronous data and the changes of the data that needs to be synchronized between users. The requirements for modern applications sometimes even go further and also provide view updates on the changed data in real time.

Handling asynchronous data and handling real-time data updates, require a major redesign of the data flow in our application. Using observable data structures, we enable our application to master the challenges of asynchronous data where we need to react to change.

Handling data in applications behaves very similarly to streams. You take input, transform it, combine it, merge it, and finally, write it into output. In systems such as this, it’s also very likely that input is in a continuous form and sometimes even of infinite duration. Just take a live feed as an example; this type of data flows continuously, and the data also flows infinitely. Functional and reactive programming are paradigms to help us deal with this kind of data in a cleaner way.

enter image description here

A simple observable subscription with value emission and a transformation

Angular 2 is reactive at its very core and the whole of the change detection and bindings are built using a reactive architecture. The input and output of components, which we’ve learned about in the previous chapter, is nothing but a data flow that is established using a reactive event-driven approach. Angular uses RxJS, a functional and reactive programming library for JavaScript, to implement this data flow. In fact, the EventEmitter, which we’ve used to send custom events from within our components, is just a wrapper around an RxJS observable.

Reactive and functional programming is exactly what we are looking for to redesign our application in order to handle asynchronous data and data changes. As we already have RxJS at hand from the production dependency of Angular, let’s use it to establish a continuous data flow from our data source into our application. The DataProvider service that is present in the data-access folder of our project provides a nice wrapper around our data store using RxJS. As we will use this service in our whole application, we can directly provide it to the bootstrap in the bootstrap.js file, as follows:

// Import Angular bootstrap function
import {bootstrap} from [email protected]/platform-browser-dynamic';
import {DataProvider} from '../data-access/data-provider';
// Import our main app component
import {App} from './app';

bootstrap(App, [
  DataProvider
]);

As a second argument to the bootstrap function of Angular, we can provide application-level dependencies, which will be available for injection in all components and directives.

Let’s now use the DataProvider service as an abstraction to obtain data from the PouchDB data store and create a new service responsible to provide project data.

We will create a new ProjectService class on the lib/project/project-service/project-service.js path, as follows:

import {Injectable, Inject} from [email protected]/core';
import {ReplaySubject} from 'rxjs/Rx';
import {DataProvider} from '../../../data-access/data-provider';

@Injectable()
export class ProjectService {
  constructor(@Inject(DataProvider) dataProvider) {
    …
  }
}

Looking at the import section of our new module, you can see that we import the necessary dependencies from the Angular core module for dependency injection. Our service class uses the @Injectable decorator so that we can provide this to the injectors of components. We also inject the DataProvider service into the constructor of our newly-created service.

The ReplaySubject class, which we import from the RxJS library, is used to make our service reactive. A subject in the RxJS world is both an observer as well as an observable. It can observe something for changes and then emit further on to all its subscribers. You can think of a subject like a proxy, where it sits in the middle between a source for changes and a group of observers. Whenever the source emits changes, the subject will notify all subscribers about these changes.

Now, the ReplaySubject class is a special kind of subject that allows you to replay a buffer of changes when new subscribers get added. This is especially useful if you always need to provide some initial data to subscribers. Imagine our data, which we’d like to get propagated into the UI. We want to immediately get the initial data when we subscribe to our service and then going forward, we also want to get notified about changes. Using a ReplySubject class, which is buffering just one change, suits this use-case perfectly.

Let’s look at the following figure, which illustrates the behavior of ReplaySubject:

Reactive programming with observable data structures

A source connected to an observer using a ReplaySubject class, which buffers the most recent value and emits on subscription

In the preceding figure, you can see that we’re connecting a ReplaySubject class to a source that is emitting value changes over time. After two emissions, an observer subscribes to our ReplaySubject class. ReplaySubject will then replay all buffered changes to the new subscriber as if these events just occurred. In this example, we use a replay buffer length of one. On subsequent value emissions, these will be directly re-emitted to the subscribers of the ReplaySubject class.

In Next Chapter we will add some logic to the constructor function in order to emit project data using a ReplaySubject class.

Let’s go back to our ProjectService class and add some logic to the constructor function in order to emit project data using a ReplaySubject class.

We will start off with some member field initialization, for which we’re going to need to implement the logic:

this.dataProvider = dataProvider;
this.projects = [];
// We're exposing a replay subject that will emit events whenever 
// the projects list change
this.change = new ReplaySubject(1);

Note that we created a new ReplaySubject class with a buffer length of one, and assign it to the member filed with the name change.

We also assign the DataProvider service, which was previously injected in the constructor parameters, to the dataProvider member field.

Now, it’s time to make use of the DataProvider service in order to subscribe for any changes within our data store. This establishes a reactive connection to our data that is stored in PouchDB:

// Setting up our functional reactive subscription to receive
// project changes from the database
this.projectsSubscription = this.dataProvider.getLiveChanges()
  // First convert the change records to actual documents
  .map((change) => change.doc)
  // Filter so that we only receive project documents
  .filter((document) => document.type === 'project')
  // Finally we subscribe to the change observer and deal with 
  // project changes in the function parameter
  .subscribe((changedProject) => {
    this.projects = this.projects.slice();
    // On every project change we need to update our projects list 
    const projectIndex = this.projects.findIndex(
      (project) => project._id === changedProject._id
    );
    if (projectIndex === -1) {
      this.projects.push(changedProject);
    } else {
      this.projects.splice(projectIndex, 1, changedProject);
    }
    // Emit an event on our replay subject
    this.change.next(this.projects);
  });

The observable that is returned by the getLiveChanges() function emits data in our data store as changes. In addition to this, this will also emit any future changes that are applied to our store after we’ve received the initial data. You can imagine a persistent connection to the database, and whenever a document is updated in the database, our observer will receive this change as a value.

Observables provide a large amount of so-called operators that allow you to transform the data stream that originated at the observable. You might already know about some of these functional operators from the ECMAScript 5 array extra functions, such as map and filter. Using operators, you can model a whole transformation flow until you finally subscribe to the data.

As we receive changed objects from the data store, we first need to transform them into document objects. This is fairly easy because each change object contains a doc property that actually holds the whole data of the changed document for which we have received an update. Using the map function, we can transform the changed objects into project objects before we return them back into the data flow:

.map((change) => change.doc)

DataProvider will provide us with data for all the documents in the store. As we are only interested in project data at the moment, we also apply a filter that filters out all the documents that are not of the project type:

.filter((document) => document.type === 'project')

Finally, we can subscribe to the transformed stream, as follows:

.subscribe((changedProject) => {})

The subscribe operator is where we terminate our observation path. This is like an endpoint at which we sit and observe. Inside our subscribe function, we listen for project document updates and incorporate them into the projects member property of our App component. This includes not only adding the new projects that were added to the document store, but it also includes updating existing projects. Each project contains a unique identifier that can be accessed by the _id property. This allows us to find the right action easily.

After updating our actual view of the projects and storing the list of projects in the projects member field, we can emit the updated list using our ReplaySubject class:

this.change.next(this.projects);

Our ProjectService class is now ready to be used, and applications components that need to obtain project data can subscribe to the exposed ReplaySubject class in order to react on these data changes.

Let’s refactor our App component in lib/app.js and get rid of the fake TaskListService that we’ve used so far:

import {Component, ViewEncapsulation, Inject} from [email protected]/core';
import {ProjectService} from './project/project-service/project-service';
import template from './app.html!text';

@Component({
  selector: 'ngc-app',
  template,
  encapsulation: ViewEncapsulation.None,
  providers: [ProjectService]
})
export class App {
  constructor(@Inject(ProjectService) projectService) {
    this.projectService = projectService;
    this.projects = [];

    // Setting up our functional reactive subscription to receive 
    // project changes
    this.projectsSubscription = projectService.change
      // We subscribe to the change observer of our service
      .subscribe((projects) => {
        this.projects = projects;
      });
  }

  // If this component gets destroyed, we need to remember to 
  // clean up the project subscription
  ngOnDestroy() {
    this.projectsSubscription.unsubscribe();
  }
}

In our App component, we now obtain a list of projects using the changed observable on our ProjectService class. Using a reactive subscription to ReplaySubject on the service, we make sure that our projects list that is stored in the App component will always be updated after any changes.

We use the OnDestroy lifecycle hook to unsubscribe from the ProjectService change observable. This is a necessary manual step if you like to do proper housekeeping in your application. Depending on the source, forgetting to unsubscribe could lead to memory leaks.

With the preceding code, we already established the base for a reactive data architecture. We observe our data store for changes and our user interface will react on them:

Reactive programming with observable data structures

Source via: dunebook.com

Suggest

Angular 2 with TypeScript for Beginners: The Pragmatic Guide

The Complete Angular 2 With Typescript Course - Update RC 6

Angular 2 and NodeJS - The Practical Guide to MEAN Stack 2.0

Learn Angular 2 Development By Building 10 Apps

Angular 2 - Superheroic Framework