Ward Bell
7 min readFeb 25, 2019

--

Wow. You know I love your articles. We are almost always on the same wave length.

Not this time. This article “wrong” on every point. I hardly know how to begin. I’ll just vent and see what you say.

The **tl;dr** for readers is this: someone — namely me — who has enormous amount of experience building real-world, line of business apps in Angular has the opposite point of view. Consider your choices carefully.

**If reactive forms are so great, why don’t react and vue have them?**

They don’t. They all use some form of template-driven approach. You won’t find anything like reactive forms in those systems. I’ve never heard anyone complain about that.

As is often sadly the case, Angular offers TWO ways to do something that others do ONE way.

OMG if we ever get rid of template-driven. Reactive is so much harder to learn and write than template-driven. That’s an indisputable fact. We already have way too many odd things to learn in Angular. If we lose the simplicity of template-driven, we’ll paint ourselves in an awful corner relative to competing libraries.

In my strong opinion, template-driven is OK (it could be better with just a few improvements), reactive forms is a gawd-awful mess, and if they were ever to deprecate one of them, let it be reactive forms.

**HTML template for Reactive is at least as nasty as Template-Driven**

You showed the template-driven template. Where is the template for the reactive form?

The reactive form class doesn’t draw itself.

You wrote about looking at the reactive form class: “we can see immediately the structure of our form in a very clean way”.

No you can’t. You see the abstract control structure. You have no idea what’s going on on screen.

In a template driven form I typically construct a ViewModel from my data (or acquire a VM indirectly from a helper service) and bind to that VM in my template. That view model has as much structure (no more, no less) than your control structure. Neither tells you what appears on screen.

In fact, with reactive you have to write BOTH the control structure AND the template and the reactive template is at least as nasty a the template driven template.

**Reactive Form Classes are Nasty**

You also picked a trivial control structure. In any real form, the control tree is complicated by nesting and initialization. That data has to come from somewhere. And you also have to get the data back out of the control structure and reshape that data for saving.

The syntax for dealing with nested arrays of controls is a nightmare.

Where is the real-world class code in your comparison?

**Difficult to nest Reactive Forms**

Everyone always shows a flat reactive form with everything it needs.

Who rolls like that? Not me. I’ve got components within components. They come. The go.

Sometimes I route into a form.

You can’t do that sanely in reactive forms. Take a look at Kara’s AngularConnect 2017 talk in which she demonstrates how challenging/near-impossible that is (even as she talks about it as if it were “really simple”).

https://www.youtube.com/watch?v=CD_t3m2WMM8

She’s brilliant. But this talk demonstrates that nesting custom controls is anything but simple. By the time you get to 30 minutes in, you’ll be freaking out and from there it just gets more and more baroque for reactive forms.

The real challenge is coordinating across the dynamic components that make up the outer most form, particularly as these components come and go.

Angular template-driven handle the complexities for you. With reactive, you have to write it all yourself. Good luck with that.

**Visibility of the Control Structure**

You made a big deal out of how, I want the implicit control structure from a template-form I have to inject it.

How big a deal is that?

1) add a reference var in the template (`#form=ngForm`)

2) Inject that into the class with `@ViewChild`

Are you telling me this is hard? Seriously?

The first step is no harder than the extra sauce you added for reactive (`[formGroup]=”loginForm”`). That’s a wash.

The second step is this.

```

@ViewChild(‘form’) form: FormGroup;

```

That’s it! Compare that to all the crap you have to write by hand to construct that `FormGroup` within the class.

The reactive class is more complicated by comparison for the simplest form and ridiculously so when the number of controls (including arrays) rises above a handful.

**Validators are no fun in either system**

OK, so you can add a validator directly to the form control. But so what? That’s not the hard part. The hard part is rendering the error.

You have to figure that out and add that rendering to your template … no matter whether you use template or reactive forms.

If you like template-driven forms, you will want a way to apply validators. I would never do it with directives because, in my strong opinion, you do not want validation logic in the view. I shouldn’t markup the HTML with validation rules.

But here is where reactive suffers too. Most validation rules are MODEL-driven, not UI-driven. Suppose `Person.firstName` has some validation constraints (including required). Well, before you can save, that validation must apply (a) _whether or not the first name is displayed_ and (b) you must have a way to ensure that the same required validation _is applied uniformly everywhere_.

You’re not solving either problem with reactive form validators.

Angular (and most application libraries) does not have a proper system of MODEL-driven form validation. We’ve had to write our own.

p.s.: Have you noticed that the reactive form’s `required` validator does NOT add the `required` attribute to the HTML. That means required validation is NOT accessible. You have to add the attribute by hand.

**Asynchronous … boo hoo**

I keep hearing about this but it has never been a serious issue for me.

Your example of a supposed reactive form advantage with cross-control validation falls flat for me. What exactly does it mean to have such a validator when one of the controls is missing. If you have a rule that the item purchase date must be before the item ship date … and you don’t show the ship date … what kind of validation are you going to do in reactive? What are you going to show the user?

It’s a disaster. And this example, btw, goes back to my point about the importance of model level validation. Only at the model level can you be sure that you actually compare purchase and ship dates, whether or not corresponding input controls appear in the UI.

**Two way bind does NOT break one-way data flow**

That is a canard. 2-way data binding is syntactic sugar for perfectly legitimate Angular construction: a property binding and an event binding. The property gets set and the event gets raised. If it’s OK to do as two bindings, it’s OK to do with `[(…)]` sugar.

And what “immutability principle” am I breaking?

With reactive, I copy data from source into a control structure, User changes update (mutate) the values in the control structure. Then I pull those values out of the control structure and send them on their way. If my data source is immutable (which is not so for everyone but I’ll play along with you), when I pull the data out of the controls, I leave the original source data untouched. I effectively create a clone or some new data structure that I pass to some service to save the changes.

Many ways to do this. If I’m using ngrx, I dispatch an action with a payload that may or may not look like the source data structure.

If I’m using `[(ngModel)]` and my source is mutable, I’m done. But, playing along again, if I want my source to be immutable, what do I do?

I create a view model from the source data and bind to that. When I’m ready to save, I extract the changes from that view model (no need to ask the form for it), and I’m pursue the same flow as for reactive.

In reactive you have to copy the data into and out of the controls. No choice. With `[(ngModel)]` you have a choice. You can mutate, in which case it is super easy. If you care about immutability, then do what reactive does and copy to/from a mutable structure. In a pinch, do this: `this.vm = { …sourceData }`. Then, when you save, you construct the save payload from `this.vm` (perhaps using it directly). It couldn’t be easier.

**Testability is the same**

>When using template-driven forms, we must create a component in order to test our forms and use one of the async testing helpers that Angular provides.

That’s misleading at best. If I must test the fidelity of the Component’s template/class interaction, then I have to follow that path for BOTH reactive and template-driven.

If I don’t (and I usually don’t), then I test the stand-alone class exactly as I would the reactive forms class. There’s nothing you can test (worth testing) in reactive form class that I’m not testing in my template-driven form class.

Given that the reactive form author had to write a LOT MORE code than the template-driven form developer, in fact there is MORE DIFFICULTY testing the reactive form class. You wrote that control structure? You better test it. Of course the template-driven developer didn’t write a control structure so there’s nothing to test in that regard. So which is harder to test again?

Prove me wrong. But make sure your proof tests logic the developer actually wrote. We’re not here to test Angular forms (reactive or template-driven). We’re here to test the code the developer wrote.

It is not often that the weight of argument is so one-sided.

This is one of the rare instances when I have NOTHING NICE TO SAY about the alternative.

I have tried several times to use reactive forms in real world apps.

I’ve ripped it out _every time_.

My message is the exact opposite of ours: ignore reactive forms; use template-driven.

You’ll be a faster, happier developer.

--

--