June 2018

Volume 33 Number 6

[The Working Programmer]

How To Be MEAN: Reactive Programming

By Ted Neward | June 2018

Welcome back again, MEANers.

In the previous two articles (msdn.com/magazine/mt829391 and msdn.com/­magazine/mt814413), I talked a great deal about what Angular refers to as “template-driven forms,” which are forms described by Angular templates and extended by the use of code to control validation and other logic. That’s all well and good, but a new concept about how to view the “flow” of information—and the resultant control exhibited in code—within a Web application is starting to seize developers’ imaginations.

I speak, of course, of “reactive” programming, and one of the great shifts between AngularJS (that is, Angular 1.0) and Angular (Angular 2.0 and beyond) is that Angular now has explicit support for a reactive style of programming, at least at the Angular level. All of which is to say, Angular supports using reactive styles of programming within Angular without having to commit to a completely reactive style of architecture outside of Angular.

Before I dive in, though, it helps to make sure everybody’s on board with what “reactive” means here.

Reactive Reactions

Fundamentally, reactive styles of programming are easy to understand, so long as you’re willing to completely invert your perspective on the traditional way of doing UI programming. (Yes, that’s a joke. But only a small one.)

In the traditional MVC-based approach for building UIs, the UI elements (buttons, text fields and the like) are created, and then … you wait. The system processes messages from the hardware, and when some combination of messages indicates that the user did something—clicked a button, typed into a text box or whatever—the code bound to the controls fires. That code typically modifies the model lying behind the UI, and the application goes back into waiting.

This “event-driven” style of programming is intrinsically asynchronous, in that the code that the programmer writes is always driven by what the user does. In some ways, it would be better to call it “indeterministic” programming, because you can’t ever know what the user will do next. Angular sought to make this easier by creating two-way binding between the UI and data model, but it can still be tricky to keep the order of things straight.

The reactive style, however, takes a more one-way approach. Controls are constructed in code (rather than in the template), and you programmatically subscribe to events emitted by those controls to respond to the user doing things. It’s not quite React-style reactive programming, but it’s pretty close, and it still permits the same kind of “immutable data model” style of programming that has enamored a percentage of the industry.

Reactive Construction

To begin, let’s look at constructing the SpeakerUI component in a reactive manner, rather than in a template-driven manner. (Here, I’m going to go with the more traditional Angular convention and call it SpeakerDetail, but the name is largely irrelevant to the discussion.) First, in order to help simplify what I’m working with, I’ll use the abbreviated form of Speaker and SpeakerService, as shown in Figure 1.

Figure 1 Speaker and SpeakerService

import { Injectable } from '@angular/core';

export class Speaker {
  id = 0
  firstName = ""
  lastName = ""
  age = 0
}

@Injectable()
export class SpeakerService {
  private speakers : Speaker[] = [
    {
      id: 1,
      firstName: 'Brian',
      lastName: 'Randell',
      age: 47,
    },
    {
      id: 2,
      firstName: 'Ted',
      lastName: 'Neward',
      age: 46,
    },
    {
      id: 3,
      firstName: 'Rachel',
      lastName: 'Appel',
      age: 39,
    }
  ]
    getSpeakers() : Promise<Array<Speaker>> {
    return Promise.resolve(this.speakers);
  }
  getSpeaker(id: number) : Promise<Speaker> {
    return Promise.resolve(this.speakers[id - 1 ]);
  }
}

Notice that the SpeakerService is using the Promise.resolve method to return a Promise that is instantly resolved. This is an easy way to mock out the service without having to build a Promise object in the longer fashion using the Promise constructor.

Next, the SpeakerDetail component is just a standard Angular component (“ng new component speaker-detail”), and the constructor should inject a SpeakerService instance as a private constructor parameter. (This was detailed in my August 2017 column, “How To Be MEAN: Angular Plays Fetch” [msdn.com/magazine/mt826349].) While you’re at it, use the constructor to call the SpeakerService’s getSpeakers method to get back the array, and store that locally into the component as a property called “speakers.” So far, this sounds a lot like the template-based component described earlier. The HTML template for this component will display a dropdown of all the speakers in the system (as obtained by getSpeakers), and then as each is selected, display the details in another set of controls underneath that dropdown. Thus, the template looks like Figure 2.

Figure 2 HTML Template

<h2>Select Speaker</h2>
<form [formGroup]="selectGroup">
<label>Speaker:
  <select formControlName="selectSpeaker">
    <option *ngFor="let speaker of speakers"
            [value]="speaker.lastName">{{speaker.lastName}}</option>
  </select>
</label>
</form>

<h2>Speaker Detail</h2>
<form [formGroup]="speakerForm" novalidate>
  <div>
    <label>First Name:
      <input formControlName="firstName">
    </label>
    <label>Last Name:
      <input formControlName="lastName">
    </label>
    <label>Age:
      <input formControlName="age">
    </label>
  </div>
</form>

It may seem strange that the alternative to “template-based” forms uses HTML templates. That’s largely because the reactive-forms approach doesn’t do away with the template, but instead removes most of the logic away from the template and into the component. This is where things start to take a left turn from the techniques examined in the previous pair of columns. The component code will actually construct a tree of control objects, and most (if not all) interaction with the controls in these two forms will happen entirely inside the code base. I won’t put event-handlers in the template. Instead, I’ll hook them up inside the component code.

But first, I need to construct the controls themselves. These will all be FormControl instances, imported from the @angular/forms module, but it can get a little tedious to construct them each (along with any required validations) by hand in code. Fortunately, Angular provides a FormBuilder class that’s designed to make things a bit more succinct and compact to construct a whole form’s worth of controls, particularly for longer (or nested) forms.

In the case of my speaker form—where I want to have a dropdown serve as a selection mechanism to choose which speaker in the list to work on—I need to do something a little different. I want to have two forms: one around the dropdown speaker-selection control, and the other containing the detail for the individual speaker. (Normally this would be two separate components in a master-detail kind of arrangement, but I haven’t covered routing yet.) Thus, I need two forms, and in Figure 3 I show how to construct them, both with the FormBuilder and without.

Figure 3 Constructing Forms

export class SpeakerDetailComponent implements OnInit {
  selectGroup : FormGroup
  speakerForm : FormGroup
  speakers : Speaker[]

  constructor(private formBuilder : FormBuilder,
              private speakerService : SpeakerService) {
    speakerService.getSpeakers().then( (res) => { this.speakers = res; });
    this.createForm();
  }

  createForm() {
    this.selectGroup = new FormGroup({
      selectSpeaker : new FormControl()
    });

    this.speakerForm = this.formBuilder.group({
      firstName: ['', Validators.required],
      lastName: ['', Validators.required],
      age: [0]
    });
  }
  // ...
}

This is, of course, only an excerpt of the class—there’s a few more things I need to add before it’s ready to ship, but this code neatly demonstrates two of the ways to construct a form. The “selectGroup” is the FormGroup that contains the one FormControl for the HTML <select> control, and I use the SpeakerService to populate a local array of Speaker instances so the <select> can populate itself. (This is actually on the template, not in the component code. If there’s a way to populate the dropdown from the component code, I’ve not found it yet in Angular 5.)

The second form, called speakerForm, is populated using the FormBuilder, which is a tiny little DSL-like language for constructing controls. Notice how I call “group” to indicate that I’m constructing a group of controls, which are effectively name-value pairs. The name is the name of the control (which must match the formControlName property in the template for each control) and the value is either an initial value, or an initial value followed by an array of validation functions (two arrays, if you want to include validation functions that run asynchronously) to run to validate the value users type in to the control.

This constructs the two forms, but selecting something in the dropdown doesn’t do anything. I need to respond to the event the dropdown will broadcast, and I can do that by hooking a function on to the “valueChanges” method of FormControl, like so:

export class SpeakerDetailComponent implements OnInit {
  // ...
  ngOnInit() {
    const speakerSelect = this.selectGroup.get('selectSpeaker');
    speakerSelect.valueChanges.forEach(
      (value:string) => {
        const speaker = this.speakers.find( (s) => s.lastName === value);
        this.populate(speaker);
      }
    );
  }
  // ...
}

Notice that the valueChanges property is actually a stream of events. Thus, I use forEach to indicate that for each event that comes through, I want to take the value to which the control has changed (the parameter to the lambda) and use that to find the speaker by last name in the array returned by the SpeakerService. I then take that Speaker instance and pass it to the populate method, shown here:

export class SpeakerDetailComponent implements OnInit {
  // ...
  populate(speaker) {
    const firstName = this.speakerForm.get('firstName');
    const lastName = this.speakerForm.get('lastName');
    const age = this.speakerForm.get('age');
    firstName.setValue(speaker.firstName);
    lastName.setValue(speaker.lastName);
    age.setValue(speaker.age);
  }
  // ...
}

The populate method simply grabs the reference to the FormControls from the speakerForm group, and uses the setValue method to populate the appropriate value from the Speaker to the appropriate control.

Reactive Analysis

A fair question to ask at this point is how this is any better than the template-based forms shown earlier. Frankly, it’s not a question of better—it’s a question of different. (The Angular docs even say this outright in the official documentation page on Reactive Forms at angular.io/guide/reactive-forms.) Capturing most of the logic in the component code (rather than in the template) may strike some developers as being more logical or cohesive, but reactive forms also have the advantage that they’re essentially a reactive “loop”: Because the controls don’t directly map to the underlying model object. The developer retains full control over what happens when, which can simplify a number of scenarios immensely.

The Angular team doesn’t believe that one approach to forms is inherently any better than the other, in fact specifically stating that both styles can be used within the same application. (I wouldn’t try to use both within the same component, however, unless you understand Angular really deeply.) The key here is that Angular supports two different styles of gathering input from users, and both are valid and viable for a good number of scenarios. But what happens if you have a large number of different forms that need to be displayed, or the form that needs to be displayed depends on the underlying model object, which can change? Angular offers yet another option, which you’ll see in the next column. Happy coding!


Ted Neward is a Seattle-based polytechnology consultant, speaker and mentor, currently working as the director of Engineering and Developer Rela-tions at Smartsheet.com. He has written a ton of articles, authored or co-authored a dozen books, and speaks all over the world. Reach him at ted@tedneward.com or read his blog at blogs.tedneward.com.