Skip to content

Commit 19d5e5a

Browse files
authored
Merge pull request #169 from icebob/custom-validation
Custom validation for fields
2 parents dd33ea0 + cd922ee commit 19d5e5a

File tree

3 files changed

+103
-69
lines changed

3 files changed

+103
-69
lines changed

dev/full/schema.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ module.exports = {
7474
required: true,
7575
hint: "Minimum 6 characters",
7676
styleClasses: "half-width",
77-
validator: validators.string
77+
validator: validators.string.locale({
78+
fieldIsRequired: "The password is required!",
79+
textTooSmall: "Password must be at least {1} characters!"
80+
})
7881
}, {
7982
type: "input",
8083
inputType: "date",

src/utils/validators.js

+74-66
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,6 @@
1-
import { isNil, isNumber, isString, isArray } from "lodash";
1+
import { defaults, isNil, isNumber, isString, isArray, isFunction } from "lodash";
22
import fecha from "fecha";
33

4-
function checkEmpty(value, required) {
5-
if (isNil(value) || value === "") {
6-
if (required)
7-
return [msg(resources.fieldIsRequired)];
8-
else
9-
return [];
10-
}
11-
return null;
12-
}
13-
14-
function msg(text) {
15-
if (text != null && arguments.length > 1)
16-
for (let i = 1; i < arguments.length; i++)
17-
text = text.replace(/\{\d+?\}/, arguments[i]);
18-
19-
return text;
20-
}
21-
224
let resources = {
235
fieldIsRequired: "This field is required!",
246
invalidFormat: "Invalid format!",
@@ -50,143 +32,162 @@ let resources = {
5032
invalidTextContainSpec: "Invalid text! Cannot contains special characters"
5133
};
5234

35+
36+
function checkEmpty(value, required, messages = resources) {
37+
if (isNil(value) || value === "") {
38+
if (required)
39+
return [msg(messages.fieldIsRequired)];
40+
else
41+
return [];
42+
}
43+
return null;
44+
}
45+
46+
function msg(text) {
47+
if (text != null && arguments.length > 1)
48+
for (let i = 1; i < arguments.length; i++)
49+
text = text.replace("{" + (i - 1) + "}", arguments[i]);
50+
51+
return text;
52+
}
53+
5354
module.exports = {
5455

5556
resources,
5657

57-
required(value, field) {
58-
return checkEmpty(value, field.required);
58+
required(value, field, model, messages = resources) {
59+
return checkEmpty(value, field.required, messages);
5960
},
6061

61-
number(value, field) {
62-
let res = checkEmpty(value, field.required); if (res != null) return res;
62+
number(value, field, model, messages = resources) {
63+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
6364

6465
let err = [];
6566
if (isNumber(value)) {
6667
if (!isNil(field.min) && value < field.min)
67-
err.push(msg(resources.numberTooSmall, field.min));
68+
err.push(msg(messages.numberTooSmall, field.min));
6869

6970
if (!isNil(field.max) && value > field.max)
70-
err.push(msg(resources.numberTooBig, field.max));
71+
err.push(msg(messages.numberTooBig, field.max));
7172

7273
} else
73-
err.push(msg(resources.invalidNumber));
74+
err.push(msg(messages.invalidNumber));
7475

7576
return err;
7677
},
7778

78-
integer(value, field) {
79-
let res = checkEmpty(value, field.required); if (res != null) return res;
79+
integer(value, field, model, messages = resources) {
80+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
8081

8182
if (!(Number(value) === value && value % 1 === 0))
82-
return [msg(resources.invalidNumber)];
83+
return [msg(messages.invalidNumber)];
8384
},
8485

85-
double(value, field) {
86-
let res = checkEmpty(value, field.required); if (res != null) return res;
86+
double(value, field, model, messages = resources) {
87+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
8788

8889
if (!isNumber(value) || isNaN(value))
89-
return [msg(resources.invalidNumber)];
90+
return [msg(messages.invalidNumber)];
9091
},
9192

92-
string(value, field) {
93-
let res = checkEmpty(value, field.required); if (res != null) return res;
93+
string(value, field, model, messages = resources) {
94+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
9495

9596
let err = [];
9697
if (isString(value)) {
9798
if (!isNil(field.min) && value.length < field.min)
98-
err.push(msg(resources.textTooSmall, value.length, field.min));
99+
err.push(msg(messages.textTooSmall, value.length, field.min));
99100

100101
if (!isNil(field.max) && value.length > field.max)
101-
err.push(msg(resources.textTooBig, value.length, field.max));
102+
err.push(msg(messages.textTooBig, value.length, field.max));
102103

103104
} else
104-
err.push(msg(resources.thisNotText));
105+
err.push(msg(messages.thisNotText));
105106

106107
return err;
107108
},
108109

109-
array(value, field) {
110+
array(value, field, model, messages = resources) {
110111
if (field.required) {
111112

112113
if (!isArray(value))
113-
return [msg(resources.thisNotArray)];
114+
return [msg(messages.thisNotArray)];
114115

115116
if (value.length == 0)
116-
return [msg(resources.fieldIsRequired)];
117+
return [msg(messages.fieldIsRequired)];
117118
}
118119

119120
if (!isNil(value)) {
120121
if (!isNil(field.min))
121122
if (value.length < field.min)
122-
return [msg(resources.selectMinItems, field.min)];
123+
return [msg(messages.selectMinItems, field.min)];
123124

124125
if (!isNil(field.max))
125126
if (value.length > field.max)
126-
return [msg(resources.selectMaxItems, field.max)];
127+
return [msg(messages.selectMaxItems, field.max)];
127128
}
128129
},
129130

130-
date(value, field) {
131-
let res = checkEmpty(value, field.required); if (res != null) return res;
131+
date(value, field, model, messages = resources) {
132+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
132133

133134
let m = new Date(value);
134135
if (!m)
135-
return [msg(resources.invalidDate)];
136+
return [msg(messages.invalidDate)];
136137

137138
let err = [];
138139

139140
if (!isNil(field.min)) {
140141
let min = new Date(field.min);
141142
if (m.valueOf() < min.valueOf())
142-
err.push(msg(resources.dateIsEarly, fecha.format(m), fecha.format(min)));
143+
err.push(msg(messages.dateIsEarly, fecha.format(m), fecha.format(min)));
143144
}
144145

145146
if (!isNil(field.max)) {
146147
let max = new Date(field.max);
147148
if (m.valueOf() > max.valueOf())
148-
err.push(msg(resources.dateIsLate, fecha.format(m), fecha.format(max)));
149+
err.push(msg(messages.dateIsLate, fecha.format(m), fecha.format(max)));
149150
}
150151

151152
return err;
152153
},
153154

154-
regexp(value, field) {
155-
let res = checkEmpty(value, field.required); if (res != null) return res;
155+
regexp(value, field, model, messages = resources) {
156+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
156157

157158
if (!isNil(field.pattern)) {
158159
let re = new RegExp(field.pattern);
159160
if (!re.test(value))
160-
return [msg(resources.invalidFormat)];
161+
return [msg(messages.invalidFormat)];
161162
}
162163
},
163164

164-
email(value, field) {
165-
let res = checkEmpty(value, field.required); if (res != null) return res;
165+
email(value, field, model, messages = resources) {
166+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
166167

167168
let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
168169
if (!re.test(value))
169-
return [msg(resources.invalidEmail)];
170+
return [msg(messages.invalidEmail)];
170171
},
171172

172-
url(value, field) {
173-
let res = checkEmpty(value, field.required); if (res != null) return res;
173+
url(value, field, model, messages = resources) {
174+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
174175

175176
let re = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g;
176177
if (!re.test(value))
177-
return [msg(resources.invalidURL)];
178+
return [msg(messages.invalidURL)];
178179
},
179180

180-
creditCard(value, field) {
181-
let res = checkEmpty(value, field.required); if (res != null) return res;
181+
creditCard(value, field, model, messages = resources) {
182+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
182183

183184
/* From validator.js code
184185
https://github.com/chriso/validator.js/blob/master/src/lib/isCreditCard.js
185186
*/
186187
const creditCard = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/;
187188
const sanitized = value.replace(/[^0-9]+/g, "");
188189
if (!creditCard.test(sanitized)) {
189-
return [msg(resources.invalidCard)];
190+
return [msg(messages.invalidCard)];
190191
}
191192
let sum = 0;
192193
let digit;
@@ -209,22 +210,29 @@ module.exports = {
209210
}
210211

211212
if (!((sum % 10) === 0 ? sanitized : false))
212-
return [msg(resources.invalidCardNumber)];
213+
return [msg(messages.invalidCardNumber)];
213214
},
214215

215-
alpha(value, field) {
216-
let res = checkEmpty(value, field.required); if (res != null) return res;
216+
alpha(value, field, model, messages = resources) {
217+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
217218

218219
let re = /^[a-zA-Z]*$/;
219220
if (!re.test(value))
220-
return [msg(resources.invalidTextContainNumber)];
221+
return [msg(messages.invalidTextContainNumber)];
221222
},
222223

223-
alphaNumeric(value, field) {
224-
let res = checkEmpty(value, field.required); if (res != null) return res;
224+
alphaNumeric(value, field, model, messages = resources) {
225+
let res = checkEmpty(value, field.required, messages); if (res != null) return res;
225226

226227
let re = /^[a-zA-Z0-9]*$/;
227228
if (!re.test(value))
228-
return [msg(resources.invalidTextContainSpec)];
229+
return [msg(messages.invalidTextContainSpec)];
229230
}
230231
};
232+
233+
Object.keys(module.exports).forEach(name => {
234+
const fn = module.exports[name];
235+
if (isFunction(fn)) {
236+
fn.locale = customMessages => (value, field, model) => fn(value, field, model, defaults(customMessages, resources));
237+
}
238+
});

test/unit/specs/utils/validators.spec.js

+25-2
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,34 @@ describe("Validators", () => {
420420

421421
it("should give the localized error message", () => {
422422
v.resources.fieldIsRequired = "A mezőt kötelező kitölteni!";
423-
v.resources.textTooSmall = "A szöveg túl rövid. {1} helyett {0}";
423+
v.resources.textTooSmall = "A szöveg túl rövid. Minimum {1} a {0} helyett";
424424

425425
expect(v.number(null, field)[0]).to.be.equal("A mezőt kötelező kitölteni!");
426-
expect(v.string("Ab", field)[0]).to.be.equal("A szöveg túl rövid. 2 helyett 5");
426+
expect(v.string("Ab", field)[0]).to.be.equal("A szöveg túl rövid. Minimum 5 a 2 helyett");
427427
});
428428

429429
});
430+
431+
describe("test local custom error messages", () => {
432+
433+
let field = {
434+
min: 5,
435+
max: 10,
436+
required: true
437+
};
438+
439+
let locNumber = v.number.locale({
440+
fieldIsRequired: "Ezt a mezőt kötelező kitölteni!",
441+
numberTooSmall: "Ez a szám nem lehet kisebb mint {0}!"
442+
});
443+
444+
it("should give the custom error message", () => {
445+
expect(locNumber(null, field)[0]).to.be.equal("Ezt a mezőt kötelező kitölteni!");
446+
expect(locNumber(2, field)[0]).to.be.equal("Ez a szám nem lehet kisebb mint 5!");
447+
});
448+
449+
it("should give the default error message", () => {
450+
expect(locNumber(30, field)[0]).to.be.equal("The number is too big! Maximum: 10");
451+
});
452+
});
430453
});

0 commit comments

Comments
 (0)