diff --git a/example/complex.js b/example/complex.js index 9b17f68..5c5d268 100644 --- a/example/complex.js +++ b/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() + } + } }); diff --git a/example/simple.js b/example/simple.js index f3b7f64..cd63cb8 100644 --- a/example/simple.js +++ b/example/simple.js @@ -25,14 +25,22 @@ var reg_form = forms.create({ required: true, validators: [validators.matchField('password')] }), - email: fields.email() + personal: { + name: fields.string({required: true, label: 'Name'}), + email: fields.email({required: true, label: 'Email'}), + address: { + address1: fields.string({required: true, label: 'Address 1'}), + address2: fields.string({label: 'Address 2'}), + city: fields.string({required: true, label: 'City'}), + state: fields.string({required: true, label: 'State'}), + zip: fields.number({required: true, label: 'ZIP'}) + } + } }); - http.createServer(function (req, res) { reg_form.handle(req, { success: function (form) { - var req_data = require('url').parse(req.url, 1).query; res.writeHead(200, {'Content-Type': 'text/html'}); res.write('
' + util.inspect(form.data) + ''); diff --git a/lib/fields.js b/lib/fields.js index 28f91a9..f45942e 100644 --- a/lib/fields.js +++ b/lib/fields.js @@ -88,7 +88,6 @@ exports.string = function (opt) { return f; }; - exports.number = function (opt) { if (!opt) { opt = {}; } var f = exports.string(opt); @@ -170,3 +169,7 @@ exports.date = function (opt) { return f; }; +exports.object = function (fields, opts) { + return forms.create(fields || {}); +}; + diff --git a/lib/forms.js b/lib/forms.js index 26017a5..340be45 100644 --- a/lib/forms.js +++ b/lib/forms.js @@ -3,7 +3,7 @@ var async = require('async'), http = require('http'), - querystring = require('querystring'), + querystring = require('qs'), parse = require('url').parse; @@ -14,6 +14,10 @@ exports.validators = require('./validators'); exports.create = function (fields) { Object.keys(fields).forEach(function (k) { + // if it's not a field object, create an object field. + if (typeof fields[k].toHTML !== 'function' && typeof fields[k] === 'object') { + fields[k] = exports.fields.object(fields[k]); + } fields[k].name = k; }); var f = { @@ -23,13 +27,17 @@ exports.create = function (fields) { b.toHTML = f.toHTML; b.fields = {}; Object.keys(f.fields).forEach(function (k) { - b.fields[k] = f.fields[k].bind(data[k]); + b.fields[k] = data[k] ? f.fields[k].bind(data[k]) : f.fields[k].bind(''); }); b.data = Object.keys(b.fields).reduce(function (a, k) { a[k] = b.fields[k].data; return a; }, {}); - b.validate = function (callback) { + b.validate = function (obj, callback) { + if (typeof obj === 'function') { + callback = obj; + } + async.forEach(Object.keys(b.fields), function (k, callback) { b.fields[k].validate(b, function (err, bound_field) { b.fields[k] = bound_field; @@ -52,7 +60,8 @@ exports.create = function (fields) { (callbacks.empty || callbacks.other)(f); } else if (obj instanceof http.IncomingMessage) { if (obj.method === 'GET') { - f.handle(parse(obj.url, 1).query, callbacks); + var qs = parse(obj.url).query; + f.handle(querystring.parse(qs), callbacks); } else if (obj.method === 'POST' || obj.method === 'PUT') { // If the app is using bodyDecoder for connect or express, // it has already put all the POST data into request.body. @@ -82,10 +91,16 @@ exports.create = function (fields) { throw new Error('Cannot handle type: ' + typeof obj); } }, - toHTML: function (iterator) { + toHTML: function (name, iterator) { var form = this; + + if (typeof name === 'function') { + iterator = name; + } + return Object.keys(form.fields).reduce(function (html, k) { - return html + form.fields[k].toHTML(k, iterator); + var kname = typeof name === 'string' ? name+'['+k+']' : k; + return html + form.fields[k].toHTML(kname, iterator); }, ''); } }; diff --git a/package.json b/package.json index 2b9aa14..39ba11a 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "test-browser": "./node_modules/.bin/browserify test-browser.js | ./node_modules/.bin/testling" }, "dependencies": { - "async": "~0.2.9" + "async": "~0.2.9", + "qs": "~0.6.5" }, "licenses": [ { @@ -45,8 +46,8 @@ }, "devDependencies": { "nodeunit": "~0.8.1", - "testling": "~1.2.2", - "browserify": "~2.25.0", + "testling": "~1.5.1", + "browserify": "~2.29.0", "nodeunit-browser-tap": "~0.0.3" } }