Sure, you should avoid building multiple forms on one page. And no, technically speaking it is not possible to submit more than one form at a time. So, we're gonna cheat. But before we dive into the specifics, first some assumptions:
We're going to use javascript to collect the fields from all forms and send it to the server through a newly created hidden form.
This is an example containing two forms:
<form action="/guests/find_assets" class="new_guest" id="search_form" method="post"> <input name="authenticity_token" type="hidden" value="ys42Gc6JdVAaRKukNDV5M+2jPhSkjCfJarSxMScBX9g=" /> <fieldset> <legend>Details of Stay</legend> <div id="search_form_container"> ...stuff ommitted... </div> </fieldset> </form> <form action="/guests" class="new_guest" id="guest_form" method="post"> <input name="authenticity_token" type="hidden" value="ys42Gc6JdVAaRKukNDV5M+2jPhSkjCfJarSxMScBX9g=" /> <fieldset style="border:0px solid white;margin-top:0px;padding-top:0px;"> <div id="accommodation_container"> ...stuff ommitted... </div> <div class="formButton"> <input id="guest_submit" name="commit" type="button" value="Save New Guest" onclick="submit_all('/guests',[$('search_form'), $('guest_form')])" /> </div> </fieldset>
Nothing special, except for the javascript call in the onclick
attribute of the button (the input element). The function submit_all
takes two arguments:
Whenever you click the button, submit_all
serializes all forms (using the Prototype library), creates a new, hidden form and submits the combined form fields through the new form.
Please note that in this specific example, there are two authenticity_token
fields. That's okay, because they contain the same value. Remember though, that only one field will be sent to the server script.
What follows is the javascript code necessary to make it all possible. If you see any strange function calls, please remember that this code relies heavily upon the Prototype library.
/** * Combine all forms in arr_forms into a new, hidden form. Submit the new form. * * @var action {string} - the form action * @var arr_forms {array} - array of form objects */ function submit_all(action, arr_forms) { var valid = true; var fields = new Hash(); arr_forms.each(function(f) { fields = fields.merge(f.serialize(true)); }); var form = createForm(action, fields); form.submit(); } /** * Create a form using a hash of fields (input names and values). * * @var action {string} - the form action * @var fields {hash} - hash of input names and values * @return {object} - returns a form object */ function createForm(action, fields) { var form = document.createElement('form'); form.style.display = 'none'; $$('body')[0].appendChild(form); form.method = 'POST'; form.action = action; createFormFields(form, fields); return form; } /** * Create hidden input fields for a form. * * @var form {object} - the form * @var fields {hash} - hash of input names and values */ function createFormFields(form, fields) { fields.each(function(field) { createInput(form, field ); }); } /** * Add a single hidden input field to a form * * @var form {object} - the form * @var hash_pair {object} - a hash pair of key and value */ function createInput(form, hash_pair) { var input = document.createElement('input'); input.setAttribute('type', 'hidden'); input.setAttribute('name', hash_pair.key); // Rails' check_box form helper uses the same name for a given checkbox and its // accompanying hidden field if (Object.isArray(hash_pair.value)) { input.setAttribute('value', hash_pair.value.max()); } else { input.setAttribute('value', hash_pair.value); } form.appendChild(input); }
Here's a version of submit_all
that addresses the LiveValidation library to validate all forms.
/** * Combine all forms in arr_forms into a new, hidden form. Submit the new form. * * @var action {string} - the form action * @var arr_forms {array} - array of form objects */ function submit_all(action, arr_forms) { var valid = true; var fields = new Hash(); arr_forms.each(function(f) { lf = LiveValidationForm.instances[f.id]; if (valid = (LiveValidation.massValidate(lf.fields) && valid) ? true : false) { fields = fields.merge(f.serialize(true)); } }); if (valid) { var form = createForm(action, fields); form.submit(); } }