Skip to content

Commit 3cddbcf

Browse files
author
Claudio Cortese
committed
Update form validation post
1 parent becfbf9 commit 3cddbcf

File tree

3 files changed

+90
-81
lines changed

3 files changed

+90
-81
lines changed

β€Ž_posts/2024-10-20-some-useful-tips-and-tricks-about-form-validation-in-javascript.mdβ€Ž

Lines changed: 90 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
layout: post
33
title: "Some Useful Tips And Tricks About Form Validation in JavaScript"
44
tags: tutorial webdev javascript
5-
image: /img/posts/yup.png
5+
image: /img/posts/zod.png
66
typewriter-delay: 20
77
---
8+
89
As time goes by, sooner or later, every developer has been tasked with building a form. πŸ› οΈ
910

1011
Well, as far as I'm concerned, that's not one of the funniest things to do. πŸ˜…
1112

12-
But it turns out that even the simpler of websites out there is going to need at least a basic contact form. πŸ€·β€β™‚οΈ
13+
But it turns out that even the simplest of websites out there is going to need at least a basic contact form. πŸ€·β€β™‚οΈ
1314

1415
And, sometimes, there are cases where you are building a really complex and big application with forms everywhere. πŸ€“
1516

@@ -19,7 +20,7 @@ But, in this post, I'm not going to show you a specific way of building a form n
1920

2021
I'm going to try to be framework agnostic as well, but I might use a couple of lines of `React` here and there, as that's what I mostly use day by day.
2122

22-
Anyway, I promise you that this will not retain you from using what I will show you in any other framework you might happen to use or even [Vanilla JS](http://vanilla-js.com/)!
23+
Anyway, I promise you that this will not prevent you from using what I will show you in any other framework you might happen to use or even [Vanilla JS](http://vanilla-js.com/)!
2324

2425
Well, at this point you may be wondering what I'm precisely going to talk about, then? 🧐
2526

@@ -29,46 +30,43 @@ Well, at this point you may be wondering what I'm precisely going to talk about,
2930
>
3031
> -- <cite>[Wikipedia][1]</cite>
3132
32-
To my advice, one of the most important task we have while building a form is to ensure that the data is proactively validated.
33+
To my advice, one of the most important tasks we have while building a form is to ensure that the data is proactively validated.
3334

3435
Of course, there MUST be validation on the backend as well, that's mandatory. ☝️
3536

3637
Never validate data only on the front-end! This might be dangerous. ☒️
3738

38-
But, actually, the real reason why you should do that, is to preserve the mental health of your user. Really! πŸ˜‚
39+
But, actually, the real reason why you should do that is to preserve the mental health of your user. Really! πŸ˜‚
3940

40-
As a matter of fact, as a user, I often run into long and/or complex and evil form that gives no hint to me about what I should do next or if the data that I provided is correct. 😈
41+
As a matter of fact, as a user, I often run into long and/or complex and evil forms that give no hint to me about what I should do next or if the data that I provided is correct. 😈
4142

42-
These are some question that I'm sure even you had while filling-out this kind of forms:
43+
These are some questions that I'm sure even you had while filling out this kind of forms:
4344

44-
1) Is there life on mars? πŸ‘½
45-
2) Will the code I wrote yesterday compile? πŸ€”
46-
3) But most importantly... Why the hell is the f**** submit button disabled?!? 🀬
45+
1. Is there life on Mars? πŸ‘½
46+
2. Will the code I wrote yesterday compile? πŸ€”
47+
3. But most importantly... Why the hell is the f\*\*\*\* submit button disabled?!? 🀬
4748

48-
Well, to be honest sometimes happens that the submit button is ALWAYS enabled (really?). 😢
49+
Well, to be honest, sometimes it happens that the submit button is ALWAYS enabled (really?). 😢
4950

5051
As a developer, I strive to do my best to avoid these frustrating situations.
5152

5253
If only we could make the user β€œfail fast, fail often”...
5354

5455
What if I told you we can accomplish this task easily?
5556

56-
## Yup to the rescue πŸš‘
57+
## Zod to the rescue πŸš‘
58+
59+
> Zod is a TypeScript-first schema declaration and validation library for JavaScript and Node.js.
5760
58-
> Yup is a JavaScript object schema validator and object parser.
59-
-- <cite>[Yup GitHub Page](https://github.com/jquense/yup)</cite>
61+
-- <cite>[Zod GitHub Page](https://github.com/colinhacks/zod)</cite>
6062

6163
### Install
6264

6365
```shell
64-
yarn add yup
66+
yarn add zod
6567
```
6668

67-
If you are using `TypeScript` you should install `@types` as well.
68-
69-
```shell
70-
yarn add -D @types/yup
71-
```
69+
If you are using `TypeScript`, you don't need to install any additional type definitions, as Zod is written in TypeScript and provides its own types.
7270

7371
### Play with it! πŸ‘¨β€πŸ’»
7472

@@ -87,21 +85,26 @@ Let's pretend we require the user to provide us these pieces of information:
8785
- Phone Number
8886
- A link to a portfolio
8987

90-
All of the fields are required but `Sex` and `Phone Number`.
88+
All of the fields are required except `Sex` and `Phone Number`.
9189

92-
We should end up writing this schema with `Yup`:
90+
We should end up writing this schema with `Zod`:
9391

9492
```js
95-
Yup.object({
96-
name: Yup.string().required(),
97-
surname: Yup.string().required(),
98-
birthDate: Yup.date().required(),
99-
sex: Yup.mixed().oneOf(['Male', 'Female']),
100-
yearsOfProficiency: Yup.number().positive().required("Don't be shy!"),
101-
email: Yup.string().email().required(),
102-
phoneNumber: Yup.string(),
103-
portfolio: Yup.string().url()
104-
})
93+
const { z } = require("zod");
94+
95+
const contactSchema = z.object({
96+
name: z.string(),
97+
surname: z.string(),
98+
birthDate: z.date(),
99+
sex: z.enum(["Male", "Female"]).optional(),
100+
yearsOfProficiency: z
101+
.number()
102+
.positive()
103+
.refine((val) => val > 0, { message: "Don't be shy!" }),
104+
email: z.string().email(),
105+
phoneNumber: z.string().optional(),
106+
portfolio: z.string().url(),
107+
});
105108
```
106109

107110
Straightforward, right?
@@ -110,83 +113,89 @@ But, what if we want to make a property required based on the value of another f
110113

111114
Let's say that we would like to be able to contact the user in some way: we don't care if by email or by calling them.
112115

113-
Thereafter, we have to make sure that at least the email OR the phone is provided.
116+
Therefore, we have to make sure that at least the email OR the phone is provided.
114117

115118
Well, that's easily done with this schema:
116119

117120
```js
118-
Yup.object({
119-
name: Yup.string().required(),
120-
surname: Yup.string().required(),
121-
birthDate: Yup.date().required(),
122-
sex: Yup.mixed().oneOf(["Male", "Female"]),
123-
yearsOfProficiency: Yup.number()
124-
.positive()
125-
.required("Don't be shy!"),
126-
email: Yup.string()
127-
.email(),
128-
phoneNumber: Yup.string()
129-
.test(
130-
"at-least-email-or-phone-number",
131-
"You should provide at least either an email or a phone number",
132-
function(value) {
133-
const email = this.parent.email;
134-
135-
if (!email || value ? .length === 0) {
136-
return false;
137-
}
138-
139-
return true;
140-
}
141-
),
142-
portfolio: Yup.string().url()
143-
})
144-
121+
const contactSchema = z
122+
.object({
123+
name: z.string(),
124+
surname: z.string(),
125+
birthDate: z.date(),
126+
sex: z.enum(["Male", "Female"]).optional(),
127+
yearsOfProficiency: z
128+
.number()
129+
.positive()
130+
.refine((val) => val > 0, { message: "Don't be shy!" }),
131+
email: z.string().email().optional(),
132+
phoneNumber: z.string().optional(),
133+
portfolio: z.string().url(),
134+
})
135+
.refine((data) => data.email || data.phoneNumber, {
136+
message: "You should provide at least either an email or a phone number",
137+
path: ["email", "phoneNumber"], // Specify which fields are causing the issue
138+
});
145139
```
146140

147-
Whit this schema in place, if we were to validate an object of this shape:
141+
With this schema in place, if we were to validate an object of this shape:
148142

149143
```js
150-
{
151-
name: 'Jimmy',
152-
surname: 'Hopkins',
153-
sex: 'Male',
154-
age: 28,
144+
const result = contactSchema.safeParse({
145+
name: "Jimmy",
146+
surname: "Hopkins",
147+
sex: "Male",
155148
yearsOfProficiency: 2,
156-
birthDate: '1991-04-29T22:00:00.000Z'
157-
}
149+
birthDate: new Date("1991-04-29"),
150+
});
151+
152+
console.log(result);
158153
```
159154

160155
We would get a nice Validation Error:
161156

162157
```
163-
ValidationError: You should provide at least either an email or a phone number
158+
{
159+
success: false,
160+
error: ZodError {
161+
issues: [
162+
{
163+
code: 'custom',
164+
message: 'You should provide at least either an email or a phone number',
165+
path: [ 'email', 'phoneNumber' ]
166+
}
167+
]
168+
}
169+
}
164170
```
165171

166172
#### Password example πŸ”
167173

168-
Another example that came to my mind is the one where the user has to enter a password twice as a mean of security.
174+
Another example that comes to mind is the one where the user has to enter a password twice as a means of security.
169175

170176
```js
171-
Yup.object({
172-
password: Yup.string().required('Password is required'),
173-
confirmPassword: Yup.string()
174-
.oneOf([Yup.ref('password'), null], "Passwords must match")
175-
.required('Password confirm is required')
176-
})
177+
const passwordSchema = z
178+
.object({
179+
password: z.string().min(6, "Password must be at least 6 characters"),
180+
confirmPassword: z.string(),
181+
})
182+
.refine((data) => data.password === data.confirmPassword, {
183+
message: "Passwords must match",
184+
path: ["confirmPassword"],
185+
});
177186
```
178187

179188
Doing that we make sure that the two passwords are exactly the same!
180189

181190
### Profit! 😎
182191

183-
All of that being said, you should be now able to validate a complex shaped object with ease.
192+
All of that being said, you should now be able to validate a complex-shaped object with ease.
184193

185-
If you are using React, you might want to try [Formik](https://jaredpalmer.com/formik/) or [React Hook Form](https://react-hook-form.com/).
186-
These two libraries are going to make your life so much easier while building forms, and leverage the possibility to use Yup as a schema validator!
194+
If you are using React, you might want to try [Formik](https://formik.org/) or [React Hook Form](https://react-hook-form.com/).
195+
These two libraries are going to make your life so much easier while building forms, and they support using Zod as a schema validator!
187196

188-
That's all for this post, see you next one!
197+
That's all for this post, see you in the next one!
189198

190199
Happy hacking until then! πŸ‘¨β€πŸ’»
191200

192-
[1]:https://en.wikipedia.org/wiki/Data_validation
201+
[1]: https://en.wikipedia.org/wiki/Data_validation

β€Žimg/posts/yup.pngβ€Ž

-6.53 KB
Binary file not shown.

β€Žimg/posts/zod.pngβ€Ž

4.94 KB
Loading

0 commit comments

Comments
Β (0)