ReactiveForms: Don't die trying. 
Tags: angular, reactiveform
Published: 2019-08-29 18:18:46

# 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.

<figure>
  <img 
 src="https://thepracticaldev.s3.amazonaws.com/i/h69p20oqbwri5ur96mh5.png" alt="The form you will build if you follow this article"/>
  <figcaption>This is how your first ReactiveForm will look.</figcaption>
</figure>

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
<!--app.component.html -->
<div class="form-control">
  <label>Name: </label>
  <input name="name" type="text" [(ngModel)]="name">
</div>
```

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
<!-- app.component.html -->

<div class="form-control">
  <label>Name: </label>
  <input name="name" 
         type="text" 
         [ngModel]="name" 
         (ngModelChange)="nameChanged($event)">
</div>
```

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

<figure>
  <img src="https://thepracticaldev.s3.amazonaws.com/i/fzsbqars8vk12cbobxbp.gif" alt="Finished form using Template Driven Form"/>
  <figcaption>After wrapping it up.</figcaption>
</figure>

## 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.

<figure>
  <img src="https://thepracticaldev.s3.amazonaws.com/i/x32ryq17hezkum14r1wa.gif" alt="Enable and disable methods in use"/>
  <figcaption>Using the enable and disable methods.</figcaption>
</figure>


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
<!-- app.component.html -->
<div class="container" [formGroup]="personForm">
  <h1>Reactive Form</h1>

  <div class="form-control">
    <label>Name: </label>
    <input type="text" formControlName="name">
  </div>

  <div id="submit-control">
    <button (click)="submit(personForm)">Submit</button>
  </div>
</div>
```

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:

- [Stackblitz - Template Driven Form](https://stackblitz.com/edit/angular-tdf-example)
- [Stackblitz - Reactive Form](https://stackblitz.com/edit/angular-rf-example)

# References:

- [Angular - Template Driven Form](https://angular.io/guide/forms)
- [Angular - Reactive Form](https://angular.io/guide/reactive-forms)

*This article was written by Daniel Marin who is a Software Developer at [This Dot](https://thisdot.co).*   

*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](https://thisdot.co).*