How do you overcome the HTML form nesting limitation? - html

I know that XHTML doesn't support nested form tags and I have already read other answers here on Stack Overflow regarding this subject, but I still haven't figured out an elegant solution to the problem.
Some say you don't need it and that they can't think of a scenario were this would be needed. Well, personally I can't think of a scenario that I haven't needed it.
Let's see a very simple example:
You are making a blog app and you have a form with some fields for creating a new post and a toolbar with "actions" like "Save", "Delete", "Cancel".
<form
action="/post/dispatch/too_bad_the_action_url_is_in_the_form_tag_even_though_conceptually_every_submit_button_inside_it_may_need_to_post_to_a_diffent_distinct_url"
method="post">
<input type="text" name="foo" /> <!-- several of those here -->
<div id="toolbar">
<input type="submit" name="save" value="Save" />
<input type="submit" name="delete" value="Delete" />
Cancel
</div>
</form>
Our objective is to write the form in a way that doesn't require JavaScript, just plain old HTML form and submit buttons.
Since the action URL is defined in the Form tag and not in each individual submit button, our only option is to post to a generic URL and then start "if...then...else" to determine the name of the button that was submitted. Not very elegant, but our only choice, since we don't want to rely on JavaScript.
The only problem is that pressing "Delete", will submit ALL the form fields on the server even though the only thing needed for this action is a Hidden input with the post-id. Not very big deal in this small example, but I have forms with hundreds (so to speak) of fields and tabs in my LOB applications that (because of requirements) have to submit everything in one-go and in any case this seems very inefficient and a waste. If form nesting was supported, I would at least be able to wrap the "Delete" submit button inside it's own form with only the post-id field.
You may say "Just implement the "Delete" as a link instead of submit". This would be wrong in so many levels, but most importantly because Side-effect actions like "Delete" here, should never be a GET request.
So my question (particularly to those that say they haven't needed form nesting) is What do YOU do? Is there any elegant solution that I'm missing or the bottom line is really "Either require JavaScript or submit everything"?

I know this is an old question, but HTML5 offers a couple new options.
The first is to separate the form from the toolbar in the markup, add another form for the delete action, and associate the buttons in the toolbar with their respective forms using the form attribute.
<form id="saveForm" action="/post/dispatch/save" method="post">
<input type="text" name="foo" /> <!-- several of those here -->
</form>
<form id="deleteForm" action="/post/dispatch/delete" method="post">
<input type="hidden" value="some_id" />
</form>
<div id="toolbar">
<input type="submit" name="save" value="Save" form="saveForm" />
<input type="submit" name="delete" value="Delete" form="deleteForm" />
Cancel
</div>
This option is quite flexible, but the original post also mentioned that it may be necessary to perform different actions with a single form. HTML5 comes to the rescue, again. You can use the formaction attribute on submit buttons, so different buttons in the same form can submit to different URLs. This example just adds a clone method to the toolbar outside the form, but it would work the same nested in the form.
<div id="toolbar">
<input type="submit" name="clone" value="Clone" form="saveForm"
formaction="/post/dispatch/clone" />
</div>
http://www.whatwg.org/specs/web-apps/current-work/#attributes-for-form-submission
The advantage of these new features is that they do all this declaratively without JavaScript. The disadvantage is that they are not supported on older browsers, so you'd have to do some polyfilling for older browsers.

I would implement this exactly as you described: submit everything to the server and do a simple if/else to check what button was clicked.
And then I would implement a Javascript call tying into the form's onsubmit event which would check before the form was submitted, and only submit the relevant data to the server (possibly through a second form on the page with the ID needed to process the thing as a hidden input, or refresh the page location with the data you need passed as a GET request, or do an Ajax post to the server, or...).
This way the people without Javascript are able to use the form just fine, but the server load is offset because the people who do have Javascript are only submitting the single piece of data needed. Getting yourself focused on only supporting one or the other really limits your options unnecessarily.
Alternatively, if you're working behind a corporate firewall or something and everybody has Javascript disabled, you might want to do two forms and work some CSS magic to make it look like the delete button is part of the first form.

can you have the forms side by side on the page, but not nested. then use CSS to make all the buttons line up pretty?
<form method="post" action="delete_processing_page">
<input type="hidden" name="id" value="foo" />
<input type="submit" value="delete" class="css_makes_me_pretty" />
</form>
<form method="post" action="add_edit_processing_page">
<input type="text" name="foo1" />
<input type="text" name="foo2" />
<input type="text" name="foo3" />
...
<input type="submit" value="post/edit" class="css_makes_me_pretty" />
</form>

HTML5 has an idea of "form owner" - the "form" attribute for input elements. It allows to emulate nested forms and will solve the issue.

Kind of an old topic, but this one might be useful for someone:
As someone mentioned above - you can use a dummy form.
I had to overcome this issue some time ago. At first, I totally forgot about this HTML restriction and just added the nested forms. The result was interesting - I lost my first form from the nested. Then it turned out to be some kind of a "trick" to simply add a dummy form (that will be removed from the browser) before the actual nested forms.
In my case it looks like this:
<form id="Main">
<form></form> <!--this is the dummy one-->
<input...><form id="Nested 1> ... </form>
<input...><form id="Nested 1> ... </form>
<input...><form id="Nested 1> ... </form>
<input...><form id="Nested 1> ... </form>
......
</form>
Works fine with Chrome, Firefox, and Safari. IE up to 9 (not sure about 10) and Opera does not detect parameters in the main form. The $_REQUEST global is empty, regardless of the inputs. Inner forms seem to work fine everywhere.
Haven't tested another suggestion described here - fieldset around nested forms.
EDIT: Frameset didn't work!
I simply added the Main form after the others (no more nested forms) and used jQuery's "clone" to duplicate inputs in the form on button click. Added .hide() to each of the cloned inputs to keep layout unchanged and now it works like a charm.

I think Jason's right. If your "Delete" action is a minimal one, make that be in a form by itself, and line it up with the other buttons so as to make the interface look like one unified form, even if it's not.
Or, of course, redesign your interface, and let people delete somewhere else entirely which doesn't require them to see the enormo-form at all.

One way I would do this without javascript would be to add a set of radio buttons that define the action to be taken:
Update
Delete
Whatever
Then the action script would take different actions depending on the value of the radio button set.
Another way would be to put two forms on the page as you suggested, just not nested. The layout may be difficult to control though:
<form name="editform" action="the_action_url" method="post">
<input type="hidden" name="task" value="update" />
<input type="text" name="foo" />
<input type="submit" name="save" value="Save" />
</form>
<form name="delform" action="the_action_url" method="post">
<input type="hidden" name="task" value="delete" />
<input type="hidden" name="post_id" value="5" />
<input type="submit" name="delete" value="Delete" />
</form>
Using the hidden "task" field in the handling script to branch appropriately.

This discussion is still of interest to me. Behind the original post are "requirements" which the OP seems to share - i.e. a form with backward compatibility. As someone whose work at the time of writing must sometimes support back to IE6 (and for years to come), I dig that.
Without pushing the framework (all organizations are going to want to reassure themselves on compatibility/robustness, and I'm not using this discussion as justification for the framework), the Drupal solutions to this issue are interesting. Drupal is also directly relevant because the framework has had a long time policy of "it should work without Javascript (only if you want)" i.e. the OP's issue.
Drupal uses it's rather extensive form.inc functions to find the triggering_element (yes, that's the name in code). See the bottom of the code listed on the API page for form_builder (if you'd like to dig into details, the source is recommended - drupal-x.xx/includes/form.inc). The builder uses automatic HTML attribute generation and, via that, can on return detect which button was pressed, and act accordingly (these can be set up to run separate processes too).
Beyond the form builder, Drupal splits data 'delete' actions into separate URLs/forms, likely for the reasons mentioned in the original post. This needs some sort of search/listing step (groan another form! but is user-friendly) as a preliminary. But this has the advantage of eliminating the "submit everything" issue. The big form with the data is used for it's intended purpose, data creation/updating (or even a 'merge' action).
In other words, one way of working around the problem is to devolve the form into two, then the problem vanishes (and the HTML methods can be corrected through a POST too).

Well, if you submit a form, browser also sends a input submit name and value.
So what yo can do is
<form
action="/post/dispatch/too_bad_the_action_url_is_in_the_form_tag_even_though_conceptually_every_submit_button_inside_it_may_need_to_post_to_a_diffent_distinct_url"
method="post">
<input type="text" name="foo" /> <!-- several of those here -->
<div id="toolbar">
<input type="submit" name="action:save" value="Save" />
<input type="submit" name="action:delete" value="Delete" />
<input type="submit" name="action:cancel" value="Cancel" />
</div>
</form>
so on server side you just look for parameter that starts width string "action:" and the rest part tells you what action to take
so when you click on button Save browser sends you something like foo=asd&action:save=Save

My solution is to have the buttons call JS functions which write and then submit forms outwith the main form
<head>
<script>
function removeMe(A, B){
document.write('<form name="removeForm" method="POST" action="Delete.php">');
document.write('<input type="hidden" name="customerID" value="' + A + '">');
document.write('<input type="hidden" name="productID" value="' + B + '">');
document.write('</form>');
document.removeForm.submit();
}
function insertMe(A, B){
document.write('<form name="insertForm" method="POST" action="Insert.php">');
document.write('<input type="hidden" name="customerID" value="' + A + '">');
document.write('<input type="hidden" name="productID" value="' + B + '">');
document.write('</form>');
document.insertForm.submit();
}
</script>
</head>
<body>
<form method="POST" action="main_form_purpose_page.php">
<input type="button" name="remove" Value="Remove" onclick="removeMe('$customerID','$productID')">
<input type="button" name="insert" Value="Insert" onclick="insertMe('$customerID','$productID')">
<input type="submit" name="submit" value="Submit">
</form>
</body>

If you really don't want to use multiple forms (as Jason sugests), then use buttons and onclick handlers.
<form id='form' name='form' action='path/to/add/edit/blog' method='post'>
<textarea name='message' id='message'>Blog message here</textarea>
<input type='submit' id='save' value='Save'>
</form>
<button id='delete'>Delete</button>
<button id='cancel'>Cancel</button>
And then in javascript (I use jQuery here for easyness) (even though it is pretty overkill for adding some onclick handlers)
$('#delete').click( function() {
document.location = 'path/to/delete/post/id';
});
$('#cancel').click( function() {
document.location = '/home/index';
});
Also I know, this will make half the page not work without javascript.

Use an iframe for the nested form. If they need to share fields, then... it's not really nested.

In response to a question posted by Yar in a comment to his own answer, I present some JavaScript which will resize an iframe. For the case of a form button, it is safe to assume the iframe will be on the same domain. This is the code I use. You will have to alter the maths/constants for your own site:
function resizeIFrame(frame)
{
try {
innerDoc = ('contentDocument' in frame) ? frame.contentDocument : frame.contentWindow.document;
if('style' in frame) {
frame.style.width = Math.min(755, Math.ceil(innerDoc.body.scrollWidth)) + 'px';
frame.style.height = Math.ceil(innerDoc.body.scrollHeight) + 'px';
} else {
frame.width = Math.ceil(innerDoc.body.scrollWidth);
frame.height = Math.ceil(innerDoc.body.scrollHeight);
}
} catch(err) {
window.status = err.message;
}
}
Then call it like this:
<iframe ... frameborder="0" onload="if(window.parent && window.parent.resizeIFrame){window.parent.resizeIFrame(this);}"></iframe>

I just came up with a nice way of doing it with jquery.
<form name="mainform">
<div id="placeholder">
<div>
</form>
<form id="nested_form" style="position:absolute">
</form>
<script>
$(document).ready(function(){
pos = $('#placeholder').position();
$('#nested_form')
.css('left', pos.left.toFixed(0)+'px')
.css('top', pos.top.toFixed(0)+'px');
});
</script>

I went around the issue by including a checkbox depending on what form the person wanted to do.
Then used 1 button to submit the whole form.

Alternatively you could assign the form actiob on the fly...might not be the best solution, but sure does relieve the server-side logic...
<form name="frm" method="post">
<input type="submit" value="One" onclick="javascript:this.form.action='1.htm'" />
<input type="submit" value="Two" onclick="javascript:this.form.action='2.htm'" />
</form>

Related

Weird behaviour of form element in bootstrap (gets removed from the DOM for some reason) [duplicate]

Is it possible to nest html forms like this
<form name="mainForm">
<form name="subForm">
</form>
</form>
so that both forms work? My friend is having problems with this, a part of the subForm works, while another part of it does not.
In a word, no. You can have several forms in a page but they should not be nested.
From the html5 working draft:
4.10.3 The form element
Content model:
Flow content, but with no form element descendants.
The HTML5 <input> form attribute can be the solution.
From http://www.w3schools.com/tags/att_input_form.asp:
The form attribute is new in HTML5.
Specifies which <form> element an <input> element belongs to. The value of this attribute must be the id attribute of a <form> element in the same document.
Scenario:
input_Form1_n1
input_Form2_n1
input_Form1_n2
input_Form2_n2
Implementation:
<form id="Form1" action="Action1.php" method="post"></form>
<form id="Form2" action="Action2.php" method="post"></form>
<input type="text" name="input_Form1_n1" form="Form1" />
<input type="text" name="input_Form2_n1" form="Form2" />
<input type="text" name="input_Form1_n2" form="Form1" />
<input type="text" name="input_Form2_n2" form="Form2" />
<input type="submit" name="button1" value="buttonVal1" form="Form1" />
<input type="submit" name="button2" value="buttonVal2" form="Form2" />
Here you'll find browser's compatibility.
It is possible to achieve the same result as nested forms, but without nesting them.
HTML5 introduced the form attribute. You can add the form attribute to form controls outside of a form to link them to a specific form element (by id).
https://www.impressivewebs.com/html5-form-attribute/
This way you can structure your html like this:
<form id="main-form" action="/main-action" method="post"></form>
<form id="sub-form" action="/sub-action" method="post"></form>
<div class="main-component">
<input type="text" name="main-property1" form="main-form" />
<input type="text" name="main-property2" form="main-form" />
<div class="sub-component">
<input type="text" name="sub-property1" form="sub-form" />
<input type="text" name="sub-property2" form="sub-form" />
<input type="submit" name="sub-save" value="Save" form="sub-form" />
</div>
<input type="submit" name="main-save" value="Save" form="main-form" />
</div>
The form attribute is supported by all modern browsers. IE does not support this though but IE is not a browser anymore, rather a compatibility tool, as confirmed by Microsoft itself: https://www.zdnet.com/article/microsoft-security-chief-ie-is-not-a-browser-so-stop-using-it-as-your-default/. It's about time we stop caring about making things work in IE.
https://caniuse.com/#feat=form-attribute
https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fae-form
From the html spec:
This feature allows authors to work around the lack of support for
nested form elements.
The second form will be ignored, see the snippet from WebKit for example:
bool HTMLParser::formCreateErrorCheck(Token* t, RefPtr<Node>& result)
{
// Only create a new form if we're not already inside one.
// This is consistent with other browsers' behavior.
if (!m_currentFormElement) {
m_currentFormElement = new HTMLFormElement(formTag, m_document);
result = m_currentFormElement;
pCloserCreateErrorCheck(t, result);
}
return false;
}
Plain html cannot allow you to do this. But with javascript you can be able to do that.
If you are using javascript/jquery you could classify your form elements with a class and then use serialize() to serialize only those form elements for the subset of the items you want to submit.
<form id="formid">
<input type="text" class="class1" />
<input type="text" class="class2">
</form>
Then in your javascript you could do this to serialize class1 elements
$(".class1").serialize();
For class2 you could do
$(".class2").serialize();
For the whole form
$("#formid").serialize();
or simply
$("#formid").submit();
If you're using AngularJS, any <form> tags inside your ng-app are replaced at runtime with ngForm directives that are designed to be nested.
In Angular forms can be nested. This means that the outer form is valid when all of the child forms are valid as well. However, browsers do not allow nesting of <form> elements, so Angular provides the ngForm directive which behaves identically to <form> but can be nested. This allows you to have nested forms, which is very useful when using Angular validation directives in forms that are dynamically generated using the ngRepeat directive. (source)
Another way to get around this problem, if you are using some server side scripting language that allows you to manipulate the posted data, is to declare your html form like this :
<form>
<input name="a_name"/>
<input name="a_second_name"/>
<input name="subform[another_name]"/>
<input name="subform[another_second_name]"/>
</form>
If you print the posted data (I will use PHP here), you will get an array like this :
//print_r($_POST) will output :
array(
'a_name' => 'a_name_value',
'a_second_name' => 'a_second_name_value',
'subform' => array(
'another_name' => 'a_name_value',
'another_second_name' => 'another_second_name_value',
),
);
Then you can just do something like :
$my_sub_form_data = $_POST['subform'];
unset($_POST['subform']);
Your $_POST now has only your "main form" data, and your subform data is stored in another variable you can manipulate at will.
Hope this helps!
As Craig said, no.
But, regarding your comment as to why:
It might be easier to use 1 <form> with the inputs and the "Update" button, and use copy hidden inputs with the "Submit Order" button in a another <form>.
Note you are not allowed to nest FORM elements!
http://www.w3.org/MarkUp/html3/forms.html
https://www.w3.org/TR/html4/appendix/changes.html#h-A.3.9 (html4 specification notes no changes regarding nesting forms from 3.2 to 4)
https://www.w3.org/TR/html4/appendix/changes.html#h-A.1.1.12 (html4 specification notes no changes regarding nesting forms from 4.0 to 4.1)
https://www.w3.org/TR/html5-diff/ (html5 specification notes no changes regarding nesting forms from 4 to 5)
https://www.w3.org/TR/html5/forms.html#association-of-controls-and-forms comments to "This feature allows authors to work around the lack of support for nested form elements.", but does not cite where this is specified, I think they are assuming that we should assume that it's specified in the html3 specification :)
You can also use formaction="" inside the button tag.
<button type="submit" formaction="/rmDog" method='post' id="rmDog">-</button>
This would be nested in the original form as a separate button.
A simple workaround is to use a iframe to hold the "nested" form.
Visually the form is nested but on the code side its in a separate html file altogether.
Even if you could get it to work in one browser, there's no guarantee that it would work the same in all browsers. So while you might be able to get it to work some of the time, you certainly wouldn't be able to get it to work all of the time.
While I don't present a solution to nested forms (it doesn't work reliably), I do present a workaround that works for me:
Usage scenario: A superform allowing to change N items at once. It has a "Submit All" button at the bottom. Each item wants to have its own nested form with a "Submit Item # N" button. But can't...
In this case, one can actually use a single form, and then have the name of the buttons be submit_1..submit_N and submitAll and handle it servers-side, by only looking at params ending in _1 if the name of the button was submit_1.
<form>
<div id="item1">
<input type="text" name="foo_1" value="23">
<input type="submit" name="submit_1" value="Submit Item #1">
</div>
<div id="item2">
<input type="text" name="foo_2" value="33">
<input type="submit" name="submit_2" value="Submit Item #2">
</div>
<input type="submit" name="submitAll" value="Submit All Items">
</form>
Ok, so not much of an invention, but it does the job.
Use empty form tag before your nested form
Tested and Worked on Firefox, Chrome
Not Tested on I.E.
<form name="mainForm" action="mainAction">
<form></form>
<form name="subForm" action="subAction">
</form>
</form>
EDIT by #adusza: As the commenters pointed out, the above code does not result in nested forms. However, if you add div elements like below, you will have subForm inside mainForm, and the first blank form will be removed.
<form name="mainForm" action="mainAction">
<div>
<form></form>
<form name="subForm" action="subAction">
</form>
</div>
</form>
Although the question is pretty old and I agree with the #everyone that nesting of form is not allowed in HTML
But this something all might want to see this
where you can hack(I'm calling it a hack since I'm sure this ain't legitimate) html to allow browser to have nested form
<form id="form_one" action="http://apple.com">
<div>
<div>
<form id="form_two" action="/">
<!-- DUMMY FORM TO ALLOW BROWSER TO ACCEPT NESTED FORM -->
</form>
</div>
<br/>
<div>
<form id="form_three" action="http://www.linuxtopia.org/">
<input type='submit' value='LINUX TOPIA'/>
</form>
</div>
<br/>
<div>
<form id="form_four" action="http://bing.com">
<input type='submit' value='BING'/>
</form>
</div>
<br/>
<input type='submit' value='Apple'/>
</div>
</form>
JS FIDDLE LINK
http://jsfiddle.net/nzkEw/10/
About nesting forms: I spent 10 years one afternoon trying to debug an ajax script.
my previous answer/example didn't account for the html markup, sorry.
<form id='form_1' et al>
<input stuff>
<submit onClick='ajaxFunction(That_Puts_form_2_In_The_ajaxContainer)'>
<td id='ajaxContainer'></td>
</form>
form_2 constantly failed saying invalid form_2.
When I moved the ajaxContainer that produced form_2 <i>outside</i> of form_1, I was back in business. It the answer the question as to why one might nest forms. I mean, really, what's the ID for if not to define which form is to be used? There must be a better, slicker work around.
No you cannot have a nested form. Instead you can open up a Modal that contains form and perform Ajax form submit.
Really not possible...
I couldn't nest form tags...
However I used this code:
<form>
OTHER FORM STUFF
<div novalidate role="form" method="post" id="fake_form_id_0" data-url="YOUR_POST_URL">
THIS FORM STUFF
</div>
</form>
with {% csrf_token %} and stuff
and applied some JS
var url = $(form_id).attr("data-url");
$.ajax({
url: url,
"type": "POST",
"data": {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'custom-param-attachment': 'value'
},
success: function (e, data) {
if (e.is_valid) {
DO STUFF
}
}
});
Today, I also got stuck in same issue, and resolve the issue I have added a user control and
on this control I use this code
<div class="divformTagEx">
</div>
<asp:Literal runat="server" ID="litFormTag" Visible="false">
'<div> <form style="margin-bottom: 3;" action="http://login.php" method="post" name="testformtag"></form> </div>'</asp:Literal>
and on PreRenderComplete event of the page call this method
private void InitializeJavaScript()
{
var script = new StringBuilder();
script.Append("$(document).ready(function () {");
script.Append("$('.divformTagEx').append( ");
script.Append(litFormTag.Text);
script.Append(" )");
script.Append(" });");
ScriptManager.RegisterStartupScript(this, GetType(), "nestedFormTagEx", script.ToString(), true);
}
I believe this will help.
Before I knew I wasn't supposed to do this I had nested forms for the purpose of having multiple submit buttons. Ran that way for 18 months, thousands of signup transactions, no one called us about any difficulties.
Nested forms gave me an ID to parse for the correct action to take. Didn't break 'til I tried to attach a field to one of the buttons and Validate complained. Wasn't a big deal to untangle it--I used an explicit stringify on the outer form so it didn't matter the submit and form didn't match. Yeah, yeah, should've taken the buttons from a submit to an onclick.
Point is there are circumstances where it's not entirely broken. But "not entirely broken" is perhaps too low a standard to shoot for :-)
[see thecode.. code format below ]2simple trick
simply dont use other inside another form tag, please use the same elements without using form tag.
see example below
"" dont use another form // just recall the enter image description hereelement in it""

i need to make an input that looks like this button

I have a button on an html page declared like so:
<button type="submit" name="action" value="sort">SAVE CHANGES</button>
My company demands we support older versions of IE, and in versions 8 and lower when the user goes to submit the form, it passes the text between the 2 button tags. So i need to use an input tag instead. Can someone help me figure out how to create an input tag where the type=submit, the name=action and the value=sort, but hte text on the button says 'SAVE CHANGES'.
Thanks!
Like this:
<input type="submit" name="action" value="SAVE CHANGES" />
However if the value="sort" is important to you perhaps you could move it to an input type="hidden" element.
An option is to use an image button with the text SAVE CHANGES on it.
<input type="image" src="save_changes.png" name="action" value="sort" />
Don't give your submit button a name, make a hidden field with the name and value you want.
<button type="submit">SAVE CHANGES</button>
<input type="hidden" name="action" value="sort" />
So, when the form is submitted, the value "action=sort" will be submitted.
The requirements seem to exclude solutions other than using <input type=image>, which has serious problems; in particular, the coordinates of the clicked location are transmitted, and probably a revision of the requirements will therefore exclude this, too.
Using JavaScript, you could tweak the data before it gets sent, or maybe use an image with an onclick handler that turns it to a button in a sense.
Normally, problems like this should be solved by modifying the server-side code. But if you have some reason why the field name (in the submitted data) must be different from the text in the button, then there does not seem to be any solution, with the given conditions.

HTML input type submit value without modifiying post value?

Lets say I have a really simple html form:
<form action="./whatever.php" method="POST">
<input type="submit" name="TheButton" value="Apples">
</form>
Which of course makes the button the user sees say Apples. I want the post request to be TheButton=Oranges ... Is there a simple way to deal with this in HTML, or will I be need to do something with a action=javascript ?
The simple way is:
<button type="submit" name="TheButton" value="Oranges">Apples</button>
… but this will break in Internet Explorer (IIRC, up to and including version 7).
If you only have one button to deal with then:
<input type="submit" value="Apples">
<input type="hidden" name="TheButton" value="Oranges">
… will work fine.
Otherwise the best approach is to use server side logic:
<input type="submit" name="TheButton_Oranges" value="Apples">
And look for a value which starts with TheButton_ and then extract the value from the name. It is an ugly hack, but it is reliable and doesn't depend on client side JS.

Embed an HTML <form> within a larger <form>?

I want to have an HTML form embedded in another form like so:
<form id="form1">
<input name="val1"/>
<form id="form2">
<input name="val2"/>
<input type="button" name="Submit Form 2 ONLY">
</form>
<input type="button" name="Submit Form 1 data including form 2">
</form>
I need to submit the entirety of form1, but when I submit form2 I only want to submit the data in form2 (not everything in form1.) Will this work?
What you have described will not work.
One workaround would be to create two forms that are not nested. You would use hidden inputs for your original parent form that duplicate the inputs from your original nested form. Then use Javascript/DOM manipulation to hook the submit event on your "parent" form, copying the values from the "nested" form into the hidden inputs in the "parent" form before allowing the form to submit.
Your form structure would look something like this (ignoring layout HTML):
<form id="form1">
<input name="val1"/>
<input name="val2" type="hidden" />
<input type="button" name="Submit Form 1 data including form 2"
onsubmit="return copyFromForm2Function()">
</form>
<form id="form2">
<input name="val2"/>
<input type="button" name="Submit Form 2 ONLY">
</form>
You cannot have nested forms (source) so this will not work.
Every form must be enclosed within a FORM element. There can be several forms in a single document, but the FORM element can't be nested
quite late but you can do this:
<form id="form1"></form>
<form id="form2"></form>
<input ***form="form1"*** name="val1"/>
<input ***form="form1"*** name="val2" type="hidden" />
<input ***form="form2"*** name="val2"/>
<input ***form="form2"*** type="button" name="Submit Form 2 ONLY">
<input ***form="form1"*** type="button" name="Submit Form 1 data including form 2"
onsubmit="return copyFromForm2Function()">
The "form" element within the input tag has been added to get around the inability to nest forms.
A possible solution : Instead of having the nested form, add an onClick event to the form2 button which will call a JS method that could get your specific items (val2 input in this case) from form1 and using AJAX or simply xmlHTTPRequests() to perform the desired POST methods.
As other people have said, you cannot nest form elements. The way I would handle something like this would be to use a single form and then group the elements with fieldsets. You can then add events to the submit buttons with javascript and enable/disable the input fields that should be submitted.
With jQuery, MooTools or any other framework this would be very simple. It will break if the client disables scripts, though.
A MooTools solution could look like this:
$('submit2').addEvent('click', function (e) {
e.stop();
$$('#fieldset1 input').set('disabled', 'disabled');
$('form').submit();
$$('#fieldset2 input').set('disabled', '');
}
Oh, and I trust you have a good reason for doing this, because to me it sounds suspiciously like bad usability :-)
I think there may be issues with the UI for this. It'd be very confusing for a user if only part of (what appears to be) a single form was submitted/saved.
Rather than nesting forms, which, as stated, is invalid, I think you need to look at perhaps implementing some AJAX calls instead to update subset of data.
Here is the definitive working answer. I didn't need to create an extra parent DIV and name it id="place_here". Naming a table cell id="place_here" and making it the parent to DIV id="div_2" was enough.
This is a brilliant little work around. Someone on another thread helped me with this.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"><head>
<title>test / crtp</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function () {
position_mdiv()();
$(window).resize(function() {
position_mdiv();
});
})
function position_mdiv(){
var pos = $('#place_here').position();
var width = $('#place_here').outerWidth();
$('#div_2').css({
position: "absolute",
top: pos.top +2 + "px",
left: (pos.left -300 + width) + "px"
});
}
</script>
<body>
<form id="CTRP_Form">
<table border="1">
<tr>
<td>
<div id="div_1"><input id="fnam" name="fnam" form="CTRP_Form" type="text"><input type=submit></div>
</td>
<td id="place_here" style="background:yellow;width:300px;padding:0px;border:solid 2px #CCC"></td>
</tr>
</table>
</form>
<div id="div_2"><form id="query_Form"><input id="MyQuery" name="MyQuery" form="query_Form" type="text"><input type=submit></form></div>
</body>
</html>
I resolved this by having multiple submit buttons in the form. The buttons reference different CGIs and brought along the additional fields that I needed to handle conditional processing in the CGIs.
Code snippet
<form name="ep" method="put" action="/cgi-bin/edit_plan.pl">
[...]
<tr>
<td><input type="text" size="20" value="red" name="RN0"></td>
<td><input type="text" size="3" value="2" name="RT0"></td>
<td><input type="submit" value="Set row 0" name="RUN0"></td>
</tr>
[...] Add as many rows as needed, increment the 0 in all places Add an ending submit for overall processing instead of row processing: <input type="submit" value="Set ALL" name="SET">
</form>
It's not valid and will in my experience produce arbitrary results.
You could work around this using Javascript's DOM functions, taking form2 out of form1, putting it into the body, submitting it and putting it back into form1.
Edit: This won't be 100% right either, as it still has nested forms. As some of the answers point out, you have to have two separate forms. You can still do this using DOM magic but with a few more turns - .see Randolpho's answer.

IE sends inner HTML when clicking on a button element

I have the following html in my webpage (simplified).
<button type="submit" name="action" value="ButtonA">Click Here</button>
In Firefox, it submits "ButtonA" as the value for the "action" form value. However, in IE7, it submits "Click Here". Is there any way to resolve this? I don't want to use input tags, because I need to be able to customize the text without affecting the values sent back to the form (localization). Basically, I want to be able to have multiple buttons with the same name, and depending on their value, do a different action when submitted. Is there any easy with to get IE to act correctly in this case?
[MORE]
Maybe I should be more clear, but I can't use
<input type="submit" name="Action" value="ButtonA">
because I need to be able to change the text displayed for localization rules, without affecting the actual value of the button that's submitted with the form.
[MORE]
To elaborate even more, Basically, I want the button to be able to say "Save" or "Sauver" depending on the language, but not have the value submitted to the server change. I also want to have multiple buttons with the same name, and depending on the value, do something, rather than depending on the button name, and testing if there is a value for that button. The code is already written from that perspective, and I just want to be able to change the displayed text in the values, without existing server side processing code.
Here is a link with a very good explanation of the problem, with some possible work arounds.
One solution is to use Javascript and a hidden field
<input type="hidden" name="actionparam" value="DoNothing">
<input type="button" onclick="OnSubmitForm('ActionA')" Value="Click Here for A" />
<input type="button" onclick="OnSubmitForm('ActionB')" Value="Click Here for B" />
function OnSubmitForm(actionname) {
var f = document.frm;
f.actionparam.value = actionname;
f.submit();
}
This works as a hidden CATPCHA also, and you can add some client validation in the javascript function
Edit:
Since you say you want to degrade to non-javascript browsers, you can use this version, that allow only one default action to the people with no javascript
The extra buttons are disabled in HTML but then re-enabled with javascript.
Tested code:
<html>
<head>
<script type="text/javascript">
<!--
function OnSubmitForm(actionname) {
var f = document.frm;
f.actionparam.value = actionname;
f.submit();
}
//-->
</SCRIPT>
</head>
<body>
<noscript>
<div style="background-color: yellow; margin: 20px;" >
You are using a limited version of the site because you don't have Javascript enabled
</div>
</noscript>
<h1>form</h1>
<form name="frm" method="post">
<input type="hidden" name="actionparam" value="DefaultAction" />
<button name="defaultbutton" type="submit">default action</button>
<button name="extrabutton1" disabled onclick="OnSubmitForm('ExtraAction1')">Extra action 1</button>
<button name="extrabutton2" disabled onclick="OnSubmitForm('ExtraAction2')">Extra action 2</button>
</form>
<h1>Results</h1>
<h2>forms collection</h2>
<ol>
<%
For x = 1 To Request.Form.count()
Response.Write("<li>" + Request.Form.key(x) + "=" + Request.Form.item(x) + "</li>")
Next
%>
</ol>
<script type="text/javascript">
<!--
document.frm.extrabutton1.disabled = false;
document.frm.extrabutton2.disabled = false;
//-->
</SCRIPT>
</body>
</html>
The usual workaround to get it working with an input-submit is to munge the value into multiple 'name' attributes, eg.:
<input type="submit" name="submit.buttonA" value="Sausage" />
<input type="submit" name="submit.buttonB" value="Mash" />
The form layer I personally use will automatically convert that as if a 'submit' control with value 'buttonA' or 'buttonB' were clicked, but it should be easy to do manually in most environments.
Just had to deal with IE6's wonderful implementation of button elements. This solution does rely on Javascript but some may find it useful.
It's particularly annoying when using the AbstractWizardController in the Spring framework as the button element is the ideal solution for the "Next", "Back" and "Finish" buttons of the wizard but don't work in IE6.
So, I ended up writing a small jQuery based fix (though it's quite trivial to convert it so that you don't have to use the jQuery library).
$(function(){
if((window.XMLHttpRequest == undefined) && (ActiveXObject != undefined)) {
$('button').click( function(event) {
var rx = /\bvalue ?= ?(".*?"|'.*?')/i;
var matches = $(this)[0].outerHTML.match( rx );
if( matches != null )
$(this).attr( 'value', matches[1].substring( 1, matches[1].length - 1 ) );
$('button').not( $(this) ).attr('disabled','disabled');
});
}
});
This will add an onclick event to all button elements. When a button is clicked it will grab the outerHTML of the button, e.g.:
<button name="playerId" value="34">Walter Payton</button>
and parse out the value attribute. Seems a lot of trouble to go in order to get the value but I found that getAttributeNode('value').value returned the innerHTML rather than the specified value attribute so wasn't very helpful. We then set the submatch of the regex as the value of the button. It should match it if you use either double or single quotes as delimiters but you do have to use some form of delimiter.
The upshot of this is that instead of "Walter Payton" being posted it will actually post "34" instead. The downside is that the button's appearance on the page will also change to "34" just before the form is submitted.
Finally the script will find all button elements except the clicked one and set their disabled attribute to be disabled. This ensures they aren't included in the POST and you don't get false positives.
As Eduardo mentions, JavaScript sounds like your best option. However, you'll need to somehow consider the fact that if a user has JavaScript disabled, you will not receive the appropriate value.
I think that you should reconsider this whole concept. I have a feeling your scenario goes something like this:
User clicks Save or Cancel
Server-side, you check for "Save" or "Cancel" value
You perform actions based on this
In reality, it shouldn't matter what the value of a Save button is. In PHP, for example, you can simply check for a value in the Save element. Regardless of whether the value is "Save" or "Sauver", you can perform the saving functionality.
I apologize if I'm way off base here. Let me know if my assumptions are accurate.
Good news: Microsoft fixed this in IE8 (standards mode only)
Bad news: It is still in beta
This jQuery fix works alright or you can hack your own JS to handle IE.
As for those suggesting input over button, that's fine, but if you want graphics or different styles on your button, then button is the only way to go.
The link you provided in the question explains that IE6 submits all the buttons with every form submission, so your app won't work with IE6 no matter what workaround you use. I tested this and verified that IE6 does indeed do this. This means that without Javascript the <button> tag is useless with IE6, and given the other limitation it is severely limited with IE7 as well. The only non-Javascript workaround I can think of is to put your <button> tags outside your main <form>, in their own forms. You could do this with <a> tags as well, but I can't recommend that since links are always GET requests and GET requests should never have side-effects, such as modifying data.
<div style="float:left">
<form name="shoppingCart" action="#c" method="GET">
<input type="hidden" name="item1" value="hat">
<input type="text" name="item1quantity" value="1"> Hat, red<br>
<input type="hidden" name="item2" value="scarf">
<input type="text" name="item2quantity" value="1"> Scarf, red<br>
<button type="submit" name="button" value="purchase">Buy now!</button>
</form>
</div>
<div style="float:right">
<form name="remove" action="#a" method="GET">
<input type="hidden" name="item" value="item1">
<button type="submit" name="button" value="delete1">Remove this item</button>
</form>
<form name="remove" action="#b" method="GET">
<input type="hidden" name="item" value="item2">
<button type="submit" name="button" value="delete2">Remove this item</button>
</form>
</div>
The downside of using multiple forms is that you are limited in what you can transmit; if the user changes the quantity in the above form that information won't be submitted when the user clicks 'remove'. But you could consider that graceful degredation for non-JS users, and use JS to synchronize the data in the main form with the hidden forms.
I think you should be using an <input type="submit" /> instead of <button>.
Use <input> instead of <button>. Otherwise, here's a description of a nice jQuery-based hack.
I don't know any way of making it work in IE7 (or IE6) without the need for JavaScript (or strange multi-form constructions).
Isn't that localized accessible to the back-end somehow either? Say, is the text coming from a database or will that just be inline in the local templates or so? You should be able to retrieve the localized version of the label both on printing and on validating the form on the back-end, shouldn't you (as much as you'd rather just use the unchanging value as you should really be able to do)?
There's always the JavaScript solution...
The following is more of a proof-of-concept that'll need some tweaking than a ready-made jQuery one-liner, but it should work without the need to change any of the HTML:
<!doctype html>
<html>
<head>
<title>Fix Buttons in IE6</title>
<script type="text/javascript">
function fixButtons() {
var btns = document.getElementsByTagName('button');
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = fixValue;
}
}
function fixValue() {
var btns = document.getElementsByTagName('button');
for (var j = 0; j < btns.length; j++) {
if (this == btns[j]) {
this.value = this.getAttributeNode('value').value;
}
else {
btns[j].parentNode.removeChild(btns[j--]);
}
}
}
</script>
</head>
<body onload="fixButtons()">
<form action="" method="get">
<button type="submit" name="action1" value="value1">Do Action 1</button>
<button type="submit" name="action2" value="value2">Do Action 2a</button>
<button type="submit" name="action2" value="value3">Do Action 2b</button>
</form>
</body>
</html>
If it only needs to work in IE7, and not in IE6, the fiXValue() function can be reduced to just:
this.value = this.getAttributeNode('value').value
Check out this ie-button-fix project which uses IE behaviors (i.e. javascript) to neatly solve the problem.
A simple workaround without using javascript is this:
<button type="submit" name="action" value="ButtonA" onclick="this.value='ButtonA'">Click Here</button>