Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adds support for nested fields. Fixes #11.

  • Loading branch information...
commit a2c6e91dfda9ec0c04509ca2c902a3387d809829 1 parent f9d7705
@ljharb ljharb authored
Showing with 88 additions and 18 deletions.
  1. +6 −1 example/complex.js
  2. +52 −17 lib/forms.js
  3. +30 −0 test/test-form.js
View
7 example/complex.js
@@ -67,7 +67,12 @@ var form = forms.create({
notes: fields.string({
widget: widgets.textarea({rows: 6})
}),
- spam_me: fields.boolean()
+ spam_me: fields.boolean(),
+ nested_1: {
+ nested_2: {
+ nested: fields.string()
+ }
+ }
});
View
69 lib/forms.js
@@ -9,6 +9,7 @@ var async = require('async'),
exports.widgets = require('./widgets');
exports.fields = require('./fields');
+var Field = exports.fields.obj;
exports.render = require('./render');
exports.validators = require('./validators');
@@ -21,30 +22,58 @@ var dotify = exports.dotify = function dotify(names) {
return filteredNames.join('.');
};
-exports.create = function (fields) {
+var setName = function setName(fields, parent_names) {
+ Object.keys(fields).forEach(function (k) {
+ var names = [].concat(parent_names).concat(k);
+ if (fields[k].field instanceof Field) {
+ fields[k].name = bracketify(names);
+ if (!fields[k].id) {
+ fields[k].id = 'id_' + dotify(names);
+ }
+ } else if (typeof fields[k] === 'object') {
+ setName(fields[k], names);
+ }
+ });
+};
+
+var bindFields = function bindFields(bFields, fields, data) {
Object.keys(fields).forEach(function (k) {
- fields[k].name = k;
+ if (fields[k].field instanceof Field) {
+ bFields[k] = fields[k].bind(data[k]);
+ } else if (typeof fields[k] === 'object') {
+ var bkFields = {};
+ bindFields(bkFields, fields[k], data[k]);
+ bFields[k] = bkFields;
+ }
});
+};
+
+exports.create = function (fields) {
+ setName(fields);
var f = {
fields: fields,
bind: function (data) {
- var b = {};
- b.toHTML = f.toHTML;
- b.fields = {};
- Object.keys(f.fields).forEach(function (k) {
- b.fields[k] = f.fields[k].bind(data[k]);
- });
+ var b = {
+ toHTML: f.toHTML,
+ fields: {}
+ };
+ bindFields(b.fields, f.fields, data);
b.data = Object.keys(b.fields).reduce(function (a, k) {
a[k] = b.fields[k].data;
return a;
}, {});
b.validate = function (callback) {
- async.forEach(Object.keys(b.fields), function (k, callback) {
- b.fields[k].validate(b, function (err, bound_field) {
- b.fields[k] = bound_field;
- callback(err);
- });
- }, function (err) {
+ async.forEach(Object.keys(b.fields), function validateFields(bFields, k, callback) {
+ if (bFields[k].field instanceof Field) {
+ bFields[k].validate(b, function (err, bound_field) {
+ bFields[k] = bound_field;
+ callback(err);
+ });
+ } else {
+ var bkFields = bFields[k];
+ async.forEach(Object.keys(bkFields), validateFields.bind(null, bkFields), function (err) { callback(err, bkFields); });
+ }
+ }.bind(null, b.fields), function (err) {
callback(err, b);
});
};
@@ -93,9 +122,15 @@ exports.create = function (fields) {
},
toHTML: function (iterator) {
var form = this;
- return Object.keys(form.fields).reduce(function (html, k) {
- return html + form.fields[k].toHTML(k, iterator);
- }, '');
+ return Object.keys(form.fields).map(function toHTML(fields, k) {
+ var html;
+ if (fields[k].field instanceof Field) {
+ html = fields[k].toHTML(fields[k].name || k, iterator);
+ } else if (typeof fields[k] === 'object') {
+ html = Object.keys(fields[k]).map(toHTML.bind(null, fields[k])).join('');
+ }
+ return html;
+ }.bind(null, form.fields)).join('');
}
};
return f;
View
30 test/test-form.js
@@ -378,3 +378,33 @@ exports.bracketify = function (test) {
test.done();
};
+exports['nested fields'] = function (test) {
+ var f = forms.create({
+ normal: forms.fields.string(),
+ outer: {
+ nested_number: forms.fields.number(),
+ inner: {
+ double_nested_array: forms.fields.array()
+ }
+ }
+ });
+ f.bind({
+ normal: 'foo',
+ outer: {
+ nested_number: 42,
+ inner: {
+ double_nested_array: ['bar', 'baz']
+ }
+ }
+ }).validate(function (err, f) {
+ test.equals(f.isValid(), true);
+ test.equals(
+ f.toHTML(),
+ '<div class="field"><label for="id_normal">Normal</label><input type="text" name="normal" id="id_normal" value="foo" /></div>' +
+ '<div class="field"><label for="id_outer.nested_number">Nested number</label><input type="text" name="outer[nested_number]" id="id_outer.nested_number" value="42" /></div>' +
+ '<div class="field"><label for="id_outer.inner.double_nested_array">Double nested array</label><input type="text" name="outer[inner][double_nested_array]" id="id_outer.inner.double_nested_array" value="bar,baz" /></div>'
+ );
+ test.done();
+ });
+};
+
Please sign in to comment.
Something went wrong with that request. Please try again.