I'm currently watching the Angular Connect 2019 videos, if anyone wants to invite me in, I would be really glad to go and watch the speakers live. While I'm watching this one Let's build a form around it, wonderful talk, you should really consider to watch it if you care about a good UX with forms; I notice something he said didn't feel quite right.
There are two form packages in Angular, there are Reactive Forms and there are Reactive Forms. Those are the only two form packages in Angular.
Agree to disagree I guess. There are two form packages in Angular, Forms, for template-driven forms, and Reactive Forms, for logic-driven forms. Most of the developers argue that Reactive Forms are better, but the complains are just too opinionated. You should notice in any case, that everything he does in the talk with the Reactive Forms, can be done with Template Forms as well, including the top form validator, and the async validator.
This you can track way back to AngularJS. Back then, we only had template-driven form, but there were not as powerful as they are with Angular, and people start creating their own version of the reactive driven form. With those, you could actually solve a problem. So, Angular developers start working on the new framework and they notice that they could use the same power engine under both strategies, and they did.
If you using Reactive Forms you should know what an AbstractControl is. If you do not, it is the base class of all other controls, including FormControl, FormGroup, and FormArray. What you may not know, is that is also used by the Template Forms. Everything you do in a Reactive Form, you can do in a Template Form because they are both based on the same tooling.
It's all about declarative vs imperative. With Template Driven Forms, you have this nice and clean declarative way to ask for a Form, without all the steps necessary to actually write the logic, but will get that almost for free.
- Are using simple forms, with no complex structures. I'm talking, login forms, addresses forms, select your favorite meal form. All of the above would fit in one nice logical object model, in which each property is a primitive value. Even if you do have a complex structure, where a property has a nested object, or an array if you know how to do it, a template-driven will save you time.
- Like declarative programming. You don't need to ask Angular for anything, just write the structure of the form, and Angular will do the model for you.
- Don't care about immutability. I'm not saying you shouldn't care, but most of the time you will mutate your data underneath regardless you are using reactive or template forms, only that with template forms you could use the banana in a box syntax to bind directly into your component, that you shouldn't.
- Are creating dynamic, and complex forms. You have a form where the user can add additional fields, and each field will use dynamic validators. It would be hard to replicate this behavior with template-driven forms.
- Like imperative programming. I understand this can be a reason, but after I've worked with both, template-driven and template-driven, I have to say that the declarative way of doing things in Template Driven Forms makes things easier to understand.
- Need a field to be an array control.
There is no such thing as the best. I think reactive driven forms have it's use cases, but they are not the most common use cases, and for those, I would prefer and advice the usage of template drive forms. You should consider asking instead, which in the best for my use case?
There are some pros, and cons for each of them, and even they share some of its greatness and weakness because both approaches use AbstractControl at the end.
- You can use custom validators in a really easy way, even async validators.
- CSS classes and pseudo-classes are added automatically for valid, invalid and pending status, allowing you to style your components in an easy way.
- You can group controls in one property.
- You can set custom errors programmatically.
- Angular provides you the data structure of the data model.
NgFormclass has a
submittedattribute that turns itself on when the user first tries to submit the form.
- It's easier to use and learn because all of its syntax and validators are inspired in the standard HTML. So, if you have attributes as
[email], Angular will know that you want to set the name of the control, this is actually required, that you want the control to be disabled, or it will validate the input as an email.
- You can enforce the usage of directive validators, using the selectors. Do you want to validate if two password matches from the top-level form?
form[appPasswordMatch]. Do you want to validate the email?
- Directive validators can use dependency injection. Because they are just directives, if you need to call a service, just inject the service.
- You can create form controls dynamically, with custom dynamic validators.
- You can create array controls.
- You have to know ahead of the shape of the form. Most of the time you do know, again: login pages, single address registration, select a meal menu, all this you can do with Template Forms, but if you don't know the shape of the model, then it will be hard to make a template form out of it.
- You won't be able to dynamically update its validators. Even if you can set errors with a reference of the form, you can add any additional validator, nor remove the ones it currently has.
- You still need to declare the template of the form. And you will use bindings, and non-standard HTML to do that. There is no built-in tool to automatically render a Reactive Form.
- There is not an easy way to render the complex form. If you want to use the Reactive Form because it's the ability to handle complex and dynamic form models, ok, but you will have a hard time trying to represent that shape in an error-prone way.
- You can't use the HTML
[disabled]property to disable a control. If you want to disable or enable a control, you will need to do it programmatically.
- You would need to track the submitted status yourself. A Reactive Drive Form is just a Form Group, so it won't have any additional properties.
- Function validators can be used in any part of the form group, and you would need to program them defensively.
- They are not strongly typed.
- It doesn't have an easy build-in tool to display errors.
- Talking about errors, errors are nested inside each control, and they don't update the error object in the parent, but only it's validity.
- Creating custom forms controls is not as simple as it should be.
I wrote one login form example, and a log up example for each of the technologies, so for now it has 4 examples. I will try to update those with another one where Reactive Forms show its muscle, a real dynamic form.
As you have may see, Template Forms works in 99% of forms, it's easy, and it has all the power of the Forms validations, including async validation. I have to admit, I also went crazy over using Reactive Forms anywhere, but I've come to realize that most of the time, they are just overkill.
Do you have some simple forms with a pre-known shape? Try to do things simples and use Template Forms, your teammates will appreciate it. Do you have some really complex forms with dynamic fields and dynamic validators for each field? I mean, it won't be easy, but I can be done easier with Reactive Forms.
Thank you for reading. I know this is an opinionated subject, and I'm looking to read your comments bellow.