Intro

This article is the first of a 3 part series about Reactive Form, and its usage in complex scenarios.

From now on, "AngularJs" refers to Angular version 1, and "Angular" refers to Angular v2+.

The article consists of three major points:

  • Introduction to AngularJs forms.
  • Transitioning to Angular Template Driven Forms.
  • Building blocks of Reactive Forms.
The form you will build if you follow this article
This is how your first ReactiveForm will look.

Without going into further detail on how forms worked in AngularJs,you used ngModel in your template to build a form. Although it worked, was it easy, testable and scalable?

Template Driven Form

Before Angular arrived, everybody was scared, because there were many breaking changes. In response to that, the Angular team created strategies that are similar to the ones from AngularJs. One good example is the Template Driven Form.

Although many things changed, you can use forms in almost the same way. You just need to use ngModel in your template to build a form.

Lets build the form shown above using Template Driven Forms. You will start in the name field, but you will repeat the same steps for every field.

Declare name property in the component.

```typescript // app.component.ts import { Component } from '@angular/core';

@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.scss' ] }) export class AppComponent { name: string } ```

Add name to ngModel.

```html

```

Now that the first input is ready, do it for the other fields.

By now, you should have your form ready. Now, lets try to print the form as you change it. You will work with ngModelChanges from ngModel, which calls a method when an input changes. Lets see how that would work in the example.

Create a nameChanged method.

typescript // app.component.ts nameChanged(name) { this.person = { ...this.person, name }; console.log(this.person); }

Add nameChanged to ngModelChanges.

```html

```

It's done! After doing it for every input, you should see something like this.

Finished form using Template Driven Form
After wrapping it up.

Reactive Form

ReactiveForm provides a model-driven approach to handling form inputs with values that change over time. Angular Docs

Is important to notice that it is based on RxJs streams, and manages its internal state in an immutable way. By allowing you to define the form programmatically, you are able to unit test it. It comes with a set of helper methods to make your life easier.

AbstractControl: This is the base abstract class for FormControl, FormArray and FormGroup. Thanks to this, you are able to compose forms with any combination of those.

FormControl: This is the main building block for a Reactive Form. You will see a lot of these, if you haven't already.

typescript name = new FormControl('');

You have a lot of properties and methods available in name, allowing you to play with the FormControl.

Enable and disable methods in use
Using the enable and disable methods.

FormArray: If you need a list of values, it will help you a lot.

typescript phones = new FormArray([ new FormControl('') ]);

FormGroup: If you have complex data structures, you are going to need this.

typescript car = new FormGroup({ brand: new FormControl(''), model: new FormControl(''), year: new FormControl(null) });

FormBuilder: FormBuilder is a service that allows you to create ReactiveForms more elegantly. It's almost always the best choice in complex scenarios.

It is totally up to you which alternative to use. This is how it would look in both cases. car and carFb behave the same way

```typescript import { FormGroup, FormControl, FormArray, FormBuilder } from '@angular/forms'

@Component({...}) class ExampleComponent { // Using Controls directly car = new FormGroup({ brand: new FormControl(''), model: new FormControl(''), year: new FormControl(null), availableColors: new FormArray([]) });

// Using FormBuilder carFb = this.fb.group({ brand: [''], model: [''], year: [null], availableColors: this.fb.array([]) });

constructor(private fb: FormBuilder) {} } ```

The main difference is that you have to inject the FormBuilder service. Also, instead of using the constructors directly, you use FormBuilder.

Now, the moment you were waiting for: how to use this. You are going to build the same form you did with Template Driven Forms, but while using Reactive Forms.

Inject FormBuilder, and create personForm with it.

```typescript // app.component.ts import { Component } from '@angular/core'; import { FormGroup, FormBuilder } from '@angular/forms';

interface Person { name: string; }

@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.scss' ] }) export class AppComponent { personForm = this.fb.group({ name: '' });

constructor(private fb: FormBuilder) {}

submit(form: FormGroup) { console.log(form.value); } } ```

Add personForm to formGroup, and name to formControlName.

```html

Reactive Form

```

Use valueChanges observable to log form changes.

typescript ngOnInit() { this.personForm.valueChanges.subscribe( (person: Person) => console.log(person) ); }

You did it! Both of your solutions should do the exact same thing. Go and finish adding the missing form controls.

Conclusion

By now, you should be convinced of the power of ReactiveForms. In future parts of this series, you'll learn how to test and validate them, which is where it starts to shine. Whether or not you like this form's implementation, it came to stay, and you should if you haven't already, start using it in your day to day as a Modern Web Developer.

Code Snippets:

References:

This article was written by Daniel Marin who is a Software Developer at This Dot.

You can follow him on Twitter at @danm_t.

Need JavaScript consulting, mentoring, or training help? Check out our list of services at This Dot Labs.