diff --git a/README.md b/README.md index 3eed30a..661a208 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ components following the same API. ### Validators * matchField +* requiresFieldIfEmpty * min * max * range diff --git a/example/complex.js b/example/complex.js index 53050e3..9b17f68 100644 --- a/example/complex.js +++ b/example/complex.js @@ -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', diff --git a/lib/validators.js b/lib/validators.js index 08987fc..0bbe836 100644 --- a/lib/validators.js +++ b/lib/validators.js @@ -30,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) { diff --git a/test/test-validators.js b/test/test-validators.js index 35bfd04..032419d 100644 --- a/test/test-validators.js +++ b/test/test-validators.js @@ -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.');