DEV Community

Why can't Form Validation be nice?

Ron Newcomb on January 01, 2020

I've used five different ways of doing form validation now, two in React and two in Angular and one with just jQuery, and I hate them all. Why i...
Collapse
 
josemunoz profile image
José Muñoz

Use yup, and maybe formik too

Collapse
 
ronnewcomb profile image
Ron Newcomb

Formik's mess was what prompted this post, particularly the bit about the onSubmit.

Collapse
 
josemunoz profile image
José Muñoz

You should include code snippets about the issues you’re describing to have a better picture

Collapse
 
lucaster profile image
lucaster

Also, what about localized number input format validation and formatting? Hell.

Collapse
 
ronnewcomb profile image
Ron Newcomb

Actually my employer lost a client over this recently. Yeah.

Collapse
 
johnny1k profile image
Ivan Manolov

What about React Hook Form? I find it elegant enough when combined with a UI lib.

Collapse
 
ealush profile image
Evyatar Alush

UI and Validations are completely different concerns. I would stay away from anything that's tied directly into one UI framework or another.

Presentation is one thing, and validation stands on its own, and you really don't want to mix the two together. Your presentation layer should only be using the output of your validations, nothing more.

I wrote a framework named Vest (also mentioned in another comment), which takes this approach into practice and separates your UI from your validation logic. You might like it.

Here are two very different examples using react hooks:
stackblitz.com/edit/vest-react-sup...
stackblitz.com/edit/vest-react-reg...

Link to Vest:
github.com/ealush/vest

Collapse
 
ronnewcomb profile image
Ron Newcomb • Edited

I've read it over twice now, but near as I can tell, it doesn't have anything to do with Forms. It's model-validation which 1) Yup does the same job more concisely, and 2) most devs (read: me) hate writing unit tests so much that the similar syntax is actually a minus :)

The annoying part of forms validation is wiring up the actual input and form event handlers without loads of boilerplate, and mapping -- changing an known-good model to/from something the webbrowser elements understand.

Vest seems more similar to Yup than anything else.

Thread Thread
 
ealush profile image
Evyatar Alush

Hey, sorry for replying late.

I can see where you're coming from. Yup and other schema validation libraries are great, and there is nothing much you can do with Vest that you can't do with them. They may even do it more concisely.

That's not my argument for using Vest.

You are right, though. Vest is not a perse form validation library, but it is also not a strictly data-model validation library.
It is not a data model validation library since it does not validate the structure of your data. You do not provide a schema to be validated, but instead describe different tests for your data - and the difference between the two is quite large.

If I had to put describe Vest in a sentence I would say something like: "App logic data validations".
The reason for this distinction is simple: Vest does a little more than just validate your data. It also gives you the tools and structure to handle your validations in your feature itself.

An inherent part of every Vest test is the error message displayed to the user upon failure, and since you can write multiple tests for the same field, you can present different error messages per field.

Vest gives you the ability to only validate some fields, for example - only the field that the user currently interacts with.

There are quite a few more features, but the general idea is this - it is not only about the data, but how your validations interact with your feature.

"The annoying part of forms validation is wiring up the actual input and form event handlers without loads of boilerplate, and mapping -- changing an known-good model to/from something the webbrowser elements understand."

So no, Vest is not strictly a form validations library, but working with it on multiple features I did notice the ease of linking a form field to validation test (or tests), and when done correctly, you only need a couple of lines to make your validations work with your inputs and form fields.

I encourage you to take a second look at this file (index.js)
stackblitz.com/edit/vest-vanilla-s...

That's really all it takes to make your form validations work with Vest, it's even easier when using a framework such as React or Vue.

Collapse
 
ronnewcomb profile image
Ron Newcomb • Edited

It's not bad at all, but I'm starting to see a lot of components - not necessarily forms - start with a paragraph of Hooks for every little thing. Seems no one wants to use a single setState anymore, but now wants to use a separate hook for every string or number?

RHF starts with 3 hooks...

Also I really hate repeating
onBlur={handleBlur}
onChange={handleChange}
on every single element. RHF and Formik both require this boilerplate.

Collapse
 
lawrencejohnson profile image
Lawrence

Can't use it for super high volume forms, but since you're going to have all of the same validation on the server, just keep simple validations presentation side and have your server side validation kick back detailed messages for the heavier stuff. A compromise on UX but its perfectly viable for many forms.

Collapse
 
graemeq profile image
Graeme Q

Vest won't help at all in this case. It's purely a lightweight test framework.

Case in point, if you look at their examples on Git, you have to then re-implement your validation rules (again) with the matches methods.

Collapse
 
ronaldhove profile image
Ronald Hove

Great article , Here is one of those solutions to make it nice

dev.to/ronaldhove/a-custom-form-bu...

Collapse
 
ronnewcomb profile image
Ron Newcomb

Haven't heard of that one either. Just from reading the landing page you linked me, I was struck by:

1) Overriding css seems hacky; I must use !important?! Srsly? How about it not use it's own classes at all if something's passed in?

2) it paints the DOM structure for literally the whole form. The approach satisfies me as an engineer but I have a feeling it won't mesh well when you have a pure designer (HTML/CSS) on the team. Or if designers made pretty input box elements or whatever in a library; can it somehow use that, not knowing the internal structure of proprietary ui components?

3) I don't see how it knows to compare passwords in the last example. Convention over configuration?

4) formControlName seems redundant between having both title and type around. (Granted, type is rarely unique, but sometimes it is, and title is almost certainly unique.) Yeah I know that's Angular's not the library's. Icon seems like it should be part of the CSS class, not in the code, and could also hang off of the type attribute.

5) passing the text of the submit button seems highly over-specific, but I understand it's making the whole form from scratch.

6) unclear why every AbstractControl must clutter the controller.

7) IIRC the validators array can also take a lambda accepting.. the value? the whole form? ... but I seem to remember Angular having a bad time if the lambda depended upon an outside var. Like it wouldn't re-render or something. Have to check my old Stackoverflow posts. Still, it's mostly good.

8) async doLogin didn't return its promise, so the form would know when teh server is done? (Oh, it's used as an event handler.)

It's got potential as a nice solution as long as #2 isn't a practical problem. Even then I nitpick the syntax as too verbose. Maybe every FormField object should add a property for the AbstractControl so they aren't running around loose in the controller. Maybe the FormField[] and the errors[] could be under a single umbrella object to avoid cluttering the controller, or, each FormField has its own errors. Maybe FormField itself could be slimmed down with reasonable defaults for formControlName and removing icon or other CSS completely. Using one's own CSS should never be so clunky. Maybe the umbrella object can have a prop for a Promise-returning submit function so it knows when to re-run validation on server return in case of server-side validation failing.

The final comment in one example regarding "we know fields X and Y are at indexes 0 and 1" screams "hacky magic numbers" to me.

Maybe #2 could be addressed by configuration: inform the library of the shape of your datepicker, of your styled inputs and validation errors, by way of some sort of template passed to forRoot(), so the form it dynamically creates matches your employer's chosen standard.

Thanks for the suggestion.

Collapse
 
ronaldhove profile image
Ronald Hove

Thanks for the feedback , you have some great points I appreciate the time you took going into detail with each one.

This is a new project I made while working on a very simple app so I will have to make the form builder more configurable to meet other people's needs

To address some of your points

1) It actually does work like that , when you pass in css classes it uses those instead , When explaining how it works , I was leaning more towards explaining the usage example , I will change the the docs to be more clear on that

2) Probably another case of better docs , the form builder uses mostly ion-components , so DOM structure should be customisable a very decent amount.

3) When your FormFeild object array contains the controllers password and confirm_password then the form builder knows its a case of password validation

4) type is the input type i.e

        <input type="text">

title is for the label , and formControlName is used by angular formbuilder when building the actual form , these could be very different

8) If you read the the scenario description , I make the assumption that there is a service api that implements a login function that returns a promise, doLogin just calls that function and when it fails the catch block handles that error. This is for the purpose of describing a use case for setting individual field errors

Collapse
 
kublermdk profile image
Michael Kubler

I love the Yii2 form validation. It's a PHP server side framework that outputs the client side code automatically for me and has a lot of control over all the weird cases like only being required if X=6 and z is set.

But as I mostly create and interact with REST APIs I don't get to use it too often.

I've just started playing with React and wondering if there's a good form validation system to go with material-ui or if I should just roll my own for my basic needs.

Collapse
 
actarian profile image
Luca Zampetti

with RxCompForm you got ReactiveForm validation with FormGroup and FormArray in a modern ES6 vanilla like environment. If you know Angular you already know how to use it.

Collapse
 
ronnewcomb profile image
Ron Newcomb

Haven't heard of that one but I'll check it out, thx.