tags:

views:

4156

answers:

7

I know that xhtml doesn't support nested form tags and I have already read other answers
here in stackoverflow 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" />
        <a href="/home/index">Cancel</a>
    </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"?

+1  A: 

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.

Ron

Ron Savage
+8  A: 

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.

One Crayon
the OP original stated no javascript
Jason
+6  A: 

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 action="post" method="delete_processing_page">
   <input type="hidden" name="id" value="foo" />
   <input type="submit" value="delete" class="css_makes_me_pretty" />
</form>

<form action="post" method="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>
Jason
Yes and it feels way too hackish. Plus in a very large page (imagine tabs and sub-tabs and nesting submit buttons in several scope levels) it's almost impossible to completely separate the elements' screen position from their position in the document.
gCoder
well, its always a balance between what you want to do and what you can do. it looks like those are the options - either one form handled on the server, or one multiple forms that become difficult to maintain - choose wisely :)
Jason
Yes, unfortunately with all those limitations in html, I'll just stick to what's supported and send the whole form to the server and afterwards use javascript unobtrusively for the clients that support it to intercept the form submition and only send what's really needed. That's the best compromise.
gCoder
+1  A: 

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.

Pim Jager
+4  A: 

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.

AmbroseChapel
A: 

Have you tought about having some buttons replaced by hyperlinks? These also work when javascript is disabled.

<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" />
        <a href="/home/do?action=delete&amp;itemid=12345">Delete</a>
        <a href="/home/index">Cancel</a>
    </div>
</form>
Kristof Neirynck
A side-effect action should never be a GET request (we don't want a link in the url bar that deletes something. So the anchor is not an option as stated in my original question.
gCoder
A: 

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

Nishi