I've got a web application, consisting mainly of a big form with information. The form is split into multiple tabs, to make it more readable for the user:
<form>
<div id="tabs">
<ul>
<li><a href="#tab1">Tab1</a></li>
<li><a href="#tab2">Tab2</a></li>
</ul>
<div id="tab1">A big table with a lot of input rows</div>
<div id="tab2">A big table with a lot of input rows</div>
</div>
</form>
The form is dynamically extended (extra rows are added to the tables). Every 10 seconds the form is serialized and synchronized with the server.
I now want to add an interactive form on one of the tabs: when a user enters a name in a field, this information is sent to the server and an id associated with that name is returned. This id is used as an identifier for some dynamically added form fields.
A quick sketchup of such a page would look like this:
<form action="bigform.php">
<div id="tabs">
<ul>
<li><a href="#tab1">Tab1</a></li>
<li><a href="#tab2">Tab2</a></li>
</ul>
<div id="tab1">A big table with a lot of input rows</div>
<div id="tab2">
<div class="associatedinfo">
<p>Information for Joe</p>
<ul>
<li><input name="associated[26][]" /></li>
<li><input name="associated[26][]" /></li>
</ul>
</div>
<div class="associatedinfo">
<p>Information for Jill</p>
<ul>
<li><input name="associated[12][]" /></li>
<li><input name="associated[12][]" /></li>
</ul>
</div>
<div id="newperson">
<form action="newform.php">
<p>Add another person:</p>
<input name="extra" /><input type="submit" value="Add" />
</form>
</div>
</div>
</div>
</form>
The above will not work: nested forms are not allowed in HTML. However, I really need to display the form on that tab: it's part of the functionality of that page. I also want the behaviour of a separate form: when the user hits return in the form field, the "Add" submit button is pressed and a submit action is triggered on the partial form.
What is the best way to solve this problem?
One thing that you could do is instead of setting the type of the "Add" input element to "submit", set it to "button" and add an id
attribute for registering a click handler:
<!-- ... -->
<div id="newperson">
<p>Add another person:</p>
<input id="extra_input" name="extra" /><input id="add_button" type="button" value="Add" />
</div>
<!-- ... -->
The reason for input type "button" is that the resulting button on the page looks exactly like a submit button, but it does nothing by default when clicked, allowing you to customize its effect. Also, input type "button" is supported in all browsers that support HTML 3.2 or later including HTML 5.
Somewhere in your Javascript you probably have a function that you wish to be called whenever the user clicks the "Add" button. Supposing that it is called addAnotherPerson
, you simply call addAnotherPerson
within a click handler:
// This is jQuery code, but all JS frameworks that I have seen have a similar feature to register a click handler on a DOM element referenced by ID.
$("#add_button").click(function (event) {
addAnotherPerson();
$("#extra_input").val(""); // reset the value
});
You also need to add a keydown handler to the "extra" text input to perform the same action when the user presses down the Enter key:
$("#extra_input").keydown(function (event) {
if (event.keyCode == 0xa || event.keyCode == 0xd) {
addAnotherPerson();
$("#extra_input").val(""); // reset the value
}
});
Be sure to add the attribute autocomplete="off"
to the "extra" text input.
The addAnotherPerson
function could send an asynchronous POST request containing the value in the "extra" text box, updating the DOM afterward if appropriate.
EDIT: If you also want to support users who have Javascript disabled, then by adding name
attributes to every submit button with a unique name
attribute value for each, your server-side application will be able to tell which button that the user clicked.
Take, for example, this code from http://www.alanflavell.org.uk/www/trysub.html:
<table>
<tr><td align=left><label for="aquavit_button"><input id="aquavit_button" type="submit" name="aquavit" value="[O]"> Aquavit</label></td></tr>
<tr><td align=left><label for="beer_button"><input id="beer_button" type="submit" name="beer" value="[O]"> Beer</label></td></tr>
<tr><td align=left><label for="champagne_button"><input id="champagne_button" type="submit" name="champagne" value="[O]"> Champagne</label></td></tr>
<tr><td align=left><label for="water_button"><input id="water_button" type="submit" name="water" value="[O]"> Dihydrogen monoxide</label></td></tr>
</table>
If the user clicks on the "[O]" button next to "Beer", then the browser sends a "beer" POST variable, but not an "aquavit", "champagne", or "water" POST variable. Try it out at http://www.alanflavell.org.uk/www/trysub.html.
One tricky issue with this technique is the case where the user submits the form by pressing the Enter key within a text input. Firefox sends a POST variable for the first submit button in the form ("aquavit" in this case) whereas Internet Explorer does not send a POST variable for any of the submit buttons. You can patch over this difference by adding a hidden, nameless submit button to the very start of the form:
<form action="bigform.php"><input type="submit" style="display:none;" />
<!-- ... -->
EDIT2: If you always make sure that the value in the "extra" text input is cleared by Javascript before the big form is submitted, then you will be able to tell if the user has Javascript disabled and they press the Enter key in the "extra" text input (indicating that they want the add-a-person action to run) by checking whether the "extra" POST variable is not empty on the server side. If it is not empty, then you can assume that the user has Javascript disabled and that they want to add a person.
Add this code:
$("#bigform").submit(function (event) {
$("#extra_input").val(""); // reset the value in the "extra" text input
return true;
});