Back to js-datatype-intermediate
11-jugaad-form-validator.js
JavaScript
1/**
2 * 📋 Jugaad Form Validator - Indian Style!
3 *
4 * India mein form bharna ek art hai! College admission ka form validate
5 * karna hai. Har field ke apne rules hain. Tujhe ek errors object return
6 * karna hai jisme galat fields ke error messages hain. Agar sab sahi hai
7 * toh empty errors object aur isValid = true.
8 *
9 * formData object:
10 * { name, email, phone, age, pincode, state, agreeTerms }
11 *
12 * Validation Rules:
13 * 1. name: must be a non-empty trimmed string, min 2 chars, max 50 chars
14 * Error: "Name must be 2-50 characters"
15 *
16 * 2. email: must be a string containing exactly one "@" and at least one "."
17 * after the "@". Use indexOf(), lastIndexOf(), includes().
18 * Error: "Invalid email format"
19 *
20 * 3. phone: must be a string of exactly 10 digits, starting with 6, 7, 8, or 9
21 * (Indian mobile numbers). Check each char is a digit.
22 * Error: "Invalid Indian phone number"
23 *
24 * 4. age: must be a number between 16 and 100 inclusive, and an integer.
25 * JUGAAD: Agar string mein number diya hai (e.g., "22"), toh parseInt()
26 * se convert karo. Agar convert nahi ho paya (isNaN), toh error.
27 * Error: "Age must be an integer between 16 and 100"
28 *
29 * 5. pincode: must be a string of exactly 6 digits, NOT starting with "0"
30 * Error: "Invalid Indian pincode"
31 *
32 * 6. state: Use optional chaining (?.) and nullish coalescing (??) -
33 * if state is null/undefined, treat as "". Must be a non-empty string.
34 * Error: "State is required"
35 *
36 * 7. agreeTerms: must be truthy (Boolean(agreeTerms) === true).
37 * Falsy values: 0, "", null, undefined, NaN, false
38 * Error: "Must agree to terms"
39 *
40 * Return:
41 * { isValid: boolean, errors: { fieldName: "error message", ... } }
42 * - isValid is true ONLY when errors object has zero keys
43 *
44 * Hint: Use typeof, Boolean(), parseInt(), isNaN(), Number.isInteger(),
45 * ?. (optional chaining), ?? (nullish coalescing), Object.keys(),
46 * startsWith(), trim(), length
47 *
48 * @param {object} formData - Form fields to validate
49 * @returns {{ isValid: boolean, errors: object }}
50 *
51 * @example
52 * validateForm({
53 * name: "Rahul Sharma", email: "rahul@gmail.com", phone: "9876543210",
54 * age: 20, pincode: "400001", state: "Maharashtra", agreeTerms: true
55 * })
56 * // => { isValid: true, errors: {} }
57 *
58 * validateForm({
59 * name: "", email: "bad-email", phone: "12345", age: 10,
60 * pincode: "0123", state: null, agreeTerms: false
61 * })
62 * // => { isValid: false, errors: { name: "...", email: "...", ... } }
63 */
64export function validateForm(formData) {
65
66 if (!formData || typeof formData !== "object") {
67 return {
68 isValid: false,
69 errors: { form: "Invalid form data" }
70 };
71 }
72
73 const errors = {};
74
75 const name = formData?.name;
76
77 if (
78 typeof name !== "string" ||
79 name.trim().length < 2 ||
80 name.trim().length > 50
81 ) {
82 errors.name = "Name must be 2-50 characters";
83 }
84
85
86 const email = formData?.email;
87
88 if (typeof email !== "string") {
89 errors.email = "Invalid email format";
90 } else {
91 const atIndex = email.indexOf("@");
92 const lastAtIndex = email.lastIndexOf("@");
93
94 if (
95 atIndex === -1 ||
96 atIndex !== lastAtIndex ||
97 !email.slice(atIndex).includes(".")
98 ) {
99 errors.email = "Invalid email format";
100 }
101 }
102
103
104 const phone = formData?.phone;
105
106 if (
107 typeof phone !== "string" ||
108 phone.length !== 10 ||
109 !["6", "7", "8", "9"].includes(phone[0])
110 ) {
111 errors.phone = "Invalid Indian phone number";
112 } else {
113 for (let char of phone) {
114 if (char < "0" || char > "9") {
115 errors.phone = "Invalid Indian phone number";
116 break;
117 }
118 }
119 }
120
121 let age = formData?.age;
122
123 if (typeof age === "string") {
124 age = parseInt(age);
125 }
126
127 if (
128 typeof age !== "number" ||
129 isNaN(age) ||
130 !Number.isInteger(age) ||
131 age < 16 ||
132 age > 100
133 ) {
134 errors.age = "Age must be an integer between 16 and 100";
135 }
136
137
138 const pincode = formData?.pincode;
139
140 if (
141 typeof pincode !== "string" ||
142 pincode.length !== 6 ||
143 pincode.startsWith("0")
144 ) {
145 errors.pincode = "Invalid Indian pincode";
146 } else {
147 for (let char of pincode) {
148 if (char < "0" || char > "9") {
149 errors.pincode = "Invalid Indian pincode";
150 break;
151 }
152 }
153 }
154
155 const state = formData?.state ?? "";
156
157 if (
158 typeof state !== "string" ||
159 state.trim().length === 0
160 ) {
161 errors.state = "State is required";
162 }
163
164 if (!Boolean(formData?.agreeTerms)) {
165 errors.agreeTerms = "Must agree to terms";
166 }
167
168 const isValid = Object.keys(errors).length === 0;
169
170 return {
171 isValid,
172 errors
173 };
174}
175
176