Skip to content

Commit

Permalink
Merge pull request #78 from caolan/either_or
Browse files Browse the repository at this point in the history
Adds "requiresFieldIfEmpty" validator
  • Loading branch information
ljharb committed Jul 28, 2013
2 parents 9dd7361 + c6df2a6 commit 2ea1fd6
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ components following the same API.
### Validators

* matchField
* requiresFieldIfEmpty
* min
* max
* range
Expand Down
6 changes: 6 additions & 0 deletions example/complex.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ var form = forms.create({
required: true,
validators: [validators.matchField('password')]
}),
phone_1: fields.string({
validators: [validators.requiresFieldIfEmpty('phone_2')]
}),
phone_2: fields.string({
validators: [validators.requiresFieldIfEmpty('phone_1')]
}),
options: fields.string({
choices: {
one: 'option one',
Expand Down
5 changes: 4 additions & 1 deletion lib/fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ exports.string = function (opt) {
b.value = raw_data;
b.data = b.parse(raw_data);
b.validate = function (form, callback) {
if (raw_data === '' || raw_data === null || typeof raw_data === 'undefined') {
var forceValidation = (b.validators || []).some(function (validator) {
return validator.forceValidation;
});
if (!forceValidation && (raw_data === '' || raw_data === null || typeof raw_data === 'undefined')) {
// don't validate empty fields, but check if required
if (b.required) { b.error = 'This field is required.'; }
process.nextTick(function () { callback(null, b); });
Expand Down
33 changes: 32 additions & 1 deletion lib/validators.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
/*jslint node: true */
'use strict';

var util = require('util');
var util = require('util');

// From https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L1238-L1257
var trim = (function () {
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF",
wsChars = '[' + ws + ']',
trimBeginRegexp = new RegExp("^" + wsChars + wsChars + "*"),
trimEndRegexp = new RegExp(wsChars + wsChars + "*$");
return function (str) {
str = str ? String(str) : '';
if (String.prototype.trim && !ws.trim()) {
return str.trim();
} else {
return String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
};
}
}());

exports.matchField = function (match_field, message) {
if (!message) { message = 'Does not match %s.'; }
Expand All @@ -14,6 +30,21 @@ exports.matchField = function (match_field, message) {
};
};

exports.requiresFieldIfEmpty = function (alternate_field, message) {
if (!message) { message = 'One of %s or %s is required.'; }
var validator = function (form, field, callback) {
var alternateBlank = trim(form.fields[alternate_field].data).length === 0,
fieldBlank = trim(field.data).length === 0;
if (alternateBlank && fieldBlank) {
callback(util.format(message, field.name, alternate_field));
} else {
callback();
}
};
validator.forceValidation = true;
return validator;
};

exports.min = function (val, message) {
if (!message) { message = 'Please enter a value greater than or equal to %s.'; }
return function (form, field, callback) {
Expand Down
33 changes: 33 additions & 0 deletions test/test-validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,39 @@ exports.matchField = function (test) {
});
};

exports.requiresFieldIfEmpty = function (test) {
var v = validators.requiresFieldIfEmpty('alternate_field', 'field 1: %s field2: %s'),
empty_fields = {
field: {name: 'field', data: ' '},
alternate_field: {name: 'alternate_field', data: ''}
},
filled_fields = {
field: {name: 'field', data: 'filled'},
alternate_field: {name: 'alternate_field', data: 'also filled'}
},
first_filled = {
field: {name: 'field', data: 'filled'},
alternate_field: {name: 'alternate_field', data: ''}
},
second_filled = {
field: {name: 'field', data: ''},
alternate_field: {name: 'alternate_field', data: 'filled'}
};
v({ fields: empty_fields }, empty_fields.field, function (err) {
test.equals(err, 'field 1: field field2: alternate_field');
v({ fields: filled_fields }, filled_fields.field, function (err) {
test.equals(err, undefined);
v({ fields: first_filled }, first_filled.field, function (err) {
test.equals(err, undefined);
v({ fields: second_filled }, second_filled.field, function (err) {
test.equals(err, undefined);
test.done();
});
});
});
});
};

exports.min = function (test) {
validators.min(100, 'Value must be greater than or equal to %s.')('form', {data: 50}, function (err) {
test.equals(err, 'Value must be greater than or equal to 100.');
Expand Down

0 comments on commit 2ea1fd6

Please sign in to comment.