96

I can best describe this as follows:

I want this (entire table in editmode and save button in every row).

<table>
    <tr>
        <td>Id</td>
        <td>Name</td>
        <td>Description</td>
        <td>&nbsp;</td>
    </tr>
    <tr>
        <td><input type="hidden" name="id" value="1" /></td>
        <td><input type="text" name="name" value="Name" /></td>
        <td><input type="text" name="description" value="Description" /></td>
        <td><input type="submit" value="Save" /></td>
    </tr>
    <tr>
        <td><input type="hidden" name="id" value="2" /></td>
        <td><input type="text" name="name" value="Name2" /></td>
        <td><input type="text" name="description" value="Description2" /></td>
        <td><input type="submit" value="Save" /></td>
    </tr>
    <!-- and more rows here ... -->
</table>

Where should I put the <form> tags?

Hash
  • 4,647
  • 5
  • 21
  • 39
Ropstah
  • 17,538
  • 24
  • 120
  • 194
  • 3
    Wrap your whole table in a form tag (and submit the whole thing) or turn your HTML table into a table *like* structure where each "row" is a form. See here: http://stackoverflow.com/a/15600151/1038812 – Matthew Mar 24 '13 at 22:18
  • 1
    See Alexx Roche answer. I think his should be the accepted answer. His answer really solves the problem. – Fandi Susanto Feb 05 '14 at 06:57
  • 1
    Alexx Roche's answer was not the best in my case, I'm actually displaying tabular information. – adg Jun 03 '16 at 01:12

10 Answers10

138

It's worth mentioning that this is possible in HTML5, using the "form" attribute for input elements:

<table>
    <tr>
        <td>Id</td>
        <td>Name</td>
        <td>Description</td>
        <td>&nbsp;</td>
    </tr>
    <tr>
        <td><form id="form1"><input type="hidden" name="id" value="1" /></form></td>
        <td><input form="form1" type="text" name="name" value="Name" /></td>
        <td><input form="form1" type="text" name="description" value="Description" /></td>
        <td><input form="form1" type="submit" value="Save" /></td>
    </tr>
    <tr>
        <td><form id="form2"><input type="hidden" name="id" value="1" /></form></td>
        <td><input form="form2" type="text" name="name" value="Name" /></td>
        <td><input form="form2" type="text" name="description" value="Description" /></td>
        <td><input form="form2" type="submit" value="Save" /></td>
    </tr>
</table>

While clean in its lack of JS and use of original elements, unfortunately this isn't working in IE10.

Update: It doesn't work in IE11 either.

tjbp
  • 3,427
  • 3
  • 24
  • 35
  • 1
    Unfortunately this is neither supported by IE _nor_ Edge: http://caniuse.com/#feat=form-attribute – Johannes Rudolph Feb 18 '17 at 15:45
  • 35
    good enough answer for those of us who don't give a damn about ie or edge – hocikto Oct 30 '18 at 14:14
  • 1
    I just noticed that an extremely old admin form (which we use daily) had improperly nested table forms and they stopped working in developer versions of both Chrome & Firefox today. I moved the `` to match the beggining tag and added the "form" attribute to all input-related fields and the row-based forms instantly started working correctly. I checked and Edge/IEMobile are the only browsers that don't support this. Microsoftrecently announced they were adopting Chromium, so this may not be a huge issue in the future. – James Moberg Feb 25 '19 at 19:34
  • 1
    If all you want to do is place a submit button outside the form, then you can make this attribute supported in IE by using the following additional attribute: `onclick="document.getElementById(this.getAttribute('form')).submit()"` – Pluto May 21 '21 at 15:20
71

I had a similar question and this answer in question HTML: table of forms? solved it for me. (Not sure if it is XHTML, but it works in an HTML5 browser.)

You can use css to give table layout to other elements.

.table { display: table; } 
.table>* { display: table-row; }
.table>*>* { display: table-cell; }

Then you use the following valid html.

<div class="table"> 
    <form>
        <div>snake<input type="hidden" name="cartitem" value="55"></div>
        <div><input name="count" value="4" /></div>
    </form>
</div>
Alexx Roche
  • 3,151
  • 1
  • 33
  • 39
40

You can't. Your only option is to divide this into multiple tables and put the form tag outside of it. You could end up nesting your tables, but this is not recommended:

<table>
  <tr><td><form>
    <table><tr><td>id</td><td>name</td>...</tr></table>
  </form></td></tr>
</table>

I would remove the tables entirely and replace it with styled html elements like divs and spans.

stereoscott
  • 13,309
  • 4
  • 33
  • 34
  • 3
    Agreed, don't use tables, use labels and form elements and CSS to align them. See http://www.websiteoptimization.com/speed/tweak/forms/ – Dan Diplo Aug 08 '09 at 19:41
  • i was afraid that it wouldn't be possible... grrr. Thanks though – Ropstah Aug 08 '09 at 19:52
  • 77
    Please, don't be "tablephobic" by default. There are plenty of cases where data must be displayed in table form that also may require a form in it. I'm currently facing one of these cases. In the end, you end up mimicking table syntax with different tags... – Pere Jul 01 '14 at 14:22
4

I wrote the below over ten years ago, when the world was a different place. These days I know of many ways to crack this particular nut, but a quick and dirty solution that will validate is to do much the same but use CSS tables for layout, not a regular HTML table.

I'd say you can, although it doesn't validate and Firefox will re-arrange the code (so what you see in 'View generated source' when using Web Developer may well surprise). I'm no expert, but putting

<form action="someexecpage.php" method="post">

just ahead of the

<tr>

and then using

</tr></form>

at the end of the row certainly gives the functionality (tested in Firefox, Chrome and IE7-9). Working for me, even if the number of validation errors it produced was a new personal best/worst! No problems seen as a consequence, and I have a fairly heavily styled table. I guess you may have a dynamically produced table, as I do, which is why parsing the table rows is a bit non-obvious for us mortals. So basically, open the form at the beginning of the row and close it just after the end of the row.

Geoff Kendall
  • 1,307
  • 12
  • 13
  • This doesn't work for me in Firefox. I wouldn't be surprised if some things work with this solution, but I suggest closely testing it. – Bryan Larsen May 11 '22 at 01:41
  • Hi Bryan, as I say, this solution is outdated. These days, you could create the table using CSS tables and have it validate just fine, work everywhere. Usually there is a much better way to achieve updatable table rows though; surround the entire table with just one form element and generate different POST values according to which row is updated. – Geoff Kendall May 11 '22 at 15:37
3

The answer of @wmantly is basicly 'the same' as I would go for at this moment. Don't use <form> tags at all and prevent 'inappropiate' tag nesting. Use javascript (in this case jQuery) to do the posting of the data, mostly you will do it with javascript, because only one row had to be updated and feedback must be given without refreshing the whole page (if refreshing the whole page, it's no use to go through all these trobules to only post a single row).

I attach a click handler to a 'update' anchor at each row, that will trigger the collection and 'submit' of the fields on the same row. With an optional data-action attribute on the anchor tag the target url of the POST can be specified.

Example html

<table>
    <tbody>
        <tr>
            <td><input type="hidden" name="id" value="row1"/><input name="textfield" type="text" value="input1" /></td>
            <td><select name="selectfield">
                <option selected value="select1-option1">select1-option1</option>
                <option value="select1-option2">select1-option2</option>
                <option value="select1-option3">select1-option3</option>
            </select></td>
            <td><a class="submit" href="#" data-action="/exampleurl">Update</a></td>
        </tr>
        <tr>
            <td><input type="hidden" name="id" value="row2"/><input name="textfield" type="text" value="input2" /></td>
            <td><select name="selectfield">
                <option selected value="select2-option1">select2-option1</option>
                <option value="select2-option2">select2-option2</option>
                <option value="select2-option3">select2-option3</option>
            </select></td>
            <td><a class="submit" href="#" data-action="/different-url">Update</a></td>
        </tr>
        <tr>
            <td><input type="hidden" name="id" value="row3"/><input name="textfield" type="text" value="input3" /></td>
            <td><select name="selectfield">
                <option selected value="select3-option1">select3-option1</option>
                <option value="select3-option2">select3-option2</option>
                <option value="select3-option3">select3-option3</option>
            </select></td>
            <td><a class="submit" href="#">Update</a></td>
        </tr>
    </tbody>
</table>

Example script

    $(document).ready(function(){
        $(".submit").on("click", function(event){
            event.preventDefault();
            var url = ($(this).data("action") === "undefined" ? "/" : $(this).data("action"));
            var row = $(this).parents("tr").first();
            var data = row.find("input, select, radio").serialize();
            $.post(url, data, function(result){ console.log(result); });
        });
    });

A JSFIddle

Piemol
  • 857
  • 8
  • 17
0

You just have to put the <form ... > tag before the <table> tag and the </form> at the end.

Hopte it helps.

Timothée Martin
  • 775
  • 4
  • 13
  • 3
    this won't work as there are form elements with the same name for every tablerow... – Ropstah Aug 08 '09 at 19:51
  • 2
    Actually it would work fine - append the row number to each item, e.g. 'r1_name', then on the next row 'r2_name', it's pretty easy to parse() these on the server – monk.e.boy Mar 08 '11 at 09:42
  • 13
    It will work fine in many cases, but if your table has 1000 rows, you probably don't want to submit the entire thing when all you want to do is update a single row. – Mike Jul 13 '14 at 23:31
0

In fact I have the problem with a form on each row of a table, with javascript (actually jquery) :

like Lothre1 said, "some browsers in the process of rendering will close form tag right after the declaration leaving inputs outside of the element"

which makes my input fields OUTSIDE the form, therefore I can't access the children of my form through the DOM with JAVASCRIPT..

typically, the following JQUERY code won't work :

$('#id_form :input').each(function(){/*action*/});
// this is supposed to select all inputS 
// within the form that has an id ='id_form'

BUT the above exemple doesn't work with the rendered HTML :

<table>
    <form id="id_form"></form>
    <tr id="tr_id">
    <td><input type="text"/></td>
    <td><input type="submit"/></td>
    </tr>
    </table>

I'm still looking for a clean solution (though using the TR 'id' parameter to walk the DOM would fix this specific problem)

dirty solution would be (for jquery):

$('#tr_id :input').each(function(){/*action*/});
// this will select all the inputS
// fields within the TR with the id='tr_id'

the above exemple will work, but it's not really "clean", because it refers to the TR instead of the FORM, AND it requires AJAX ...

EDIT : complete process with jquery/ajax would be :

//init data string
// the dummy init value (1=1)is just here 
// to avoid dealing with trailing &
// and should not be implemented
// (though it works)
var data_str = '1=1'; 
// for each input in the TR
$('#tr_id :input').each(function(){

 //retrieve field name and value from the DOM
 var field = $(this).attr('name');
 var value = $(this).val();

 //iterate the string to pass the datas
 // so in the end it will render s/g like
 // "1=1&field1_name=value1&field2_name=value2"...
 data_str += '&' + field + '=' + value; 


});

//Sendind fields datawith ajax 
// to be treated 
$.ajax({
 type:"POST",
 url: "target_for_the_form_treatment",
 data:data_string,
 success:function(msg){
    /*actions on success of the request*/
 });
});

this way, the "target_for_the_form_treatment" should receive POST data as if a form was sent to him (appart from the post[1] = 1, but to implement this solution i would recommand dealing with the trailing '&' of the data_str instead).

still I don't like this solution, but I'm forced to use TABLE structure because of the dataTables jquery plugin...

renard
  • 11
  • 1
  • 1
    This is more of a comment than an answer... especially because you don't explain how `$('#tr_id :input').each(function(){/*action*/});` solves the problem. – Ben D Oct 11 '12 at 17:13
  • well i've edited the message to detail the different protions of jquery, but i think this is more than a comment : javascript is one of the reason why even though POST data will be sent to the server, DOM hierarchy is not respected ... – renard Oct 11 '12 at 22:45
  • You've solved the question of how to access the `input`s through Javascript, but that was never the problem in the first place... the problem is that the OP wants each row of a table to be a submit-able form. Your post does not answer that question. You **could** convert it into an answer by showing how to use JQuery/javascript to submit discrete blocks of the table (by, say, having the `submit` button on each row grab the values from the elements on it's parent `tr` and then pass these values into an AJAX post). There are other ways to do it, you need to show how it addresses the OP's problem – Ben D Oct 11 '12 at 23:08
0

Im late to the party, but this worked great for me and the code should explain itself;

<script type="text/javascript">
    function formAJAX(btn){
        var $form = $(btn).closest('[action]');
        var str = $form.find('[name]').serialize();
        $.post($form.attr('action'), str, function(data){
            //do stuff
        });
    }
<script>

HTML:

<tr action="scriptURL.php">
    <td>
        Field 1:<input type="text" name="field1"/>
    </td>
    <td>
        Field 2:<input type="text" name="field2" />
    </td>
    <td><button type="button" onclick="formAJAX(this)">Update</button></td>
</tr>
wmantly
  • 21
  • 1
  • 2
  • @pbalaga: See edit history, but since it's been edited, the comment was indeed obsolete, so I deleted it. – t0mppa Apr 23 '14 at 12:33
-1

If you try to add a form warping a tr element like this

<table>
<form>
<tr>
<td><input type="text"/></td>
<td><input type="submit"/></td>
</tr>
</form>
</table>

some browsers in the process of rendering will close form tag right after the declaration leaving inputs outside of the element

something like this

<table>
    <form></form>
    <tr>
    <td><input type="text"/></td>
    <td><input type="submit"/></td>
    </tr>
    </table>

This issue is still valid for warping multiple table cells

As stereoscott said above, nesting tables are a possible solution which is not recommended. Avoid using tables.

Lothre1
  • 3,523
  • 7
  • 43
  • 64
-1
<table > 
<thead > 
   <tr>
    <th>No</th><th>ID</th><th>Name</th><th>Ip</th><th>Save</th> 
   </tr>
</thead>
<tbody id="table_data"> 
         <tr>
            <td> 
                <form method="POST" autocomplete="off" id="myForm_207" action="save.php">
                    <input type="hidden" name="pvm" value="207"> 
                    <input type="hidden" name="customer_records_id" value="2"> 
                    <input type="hidden" name="name_207" id="name_207" value="BURÇİN MERYEM ONUK"> 
                    <input type="hidden" name="ip_207" id="ip_207" value="89.19.24.118"> 

                </form> 
                1 
            </td> 
            <td> 
                207 
            </td> 
            <td> 
                <input type="text" id="nameg_207" value="BURÇİN MERYEM ONUK"> 
            </td> 
            <td> 
                <input type="text" id="ipg_207" value="89.19.24.118"> 
            </td> 
            <td>
                <button type="button" name="Kaydet_207" class="searchButton" onclick="postData('myForm_207','207')">SAVE</button>
            </td>
        </tr> 
        <tr>
            <td> 
                <form method="POST" autocomplete="off" id="myForm_209" action="save.php">
                    <input type="hidden" name="pvm" value="209"> 
                    <input type="hidden" name="customer_records_id" value="2"> 
                    <input type="hidden" name="name_209" id="name_209" value="BALA BAŞAK KAN"> 
                    <input type="hidden" name="ip_209" id="ip_209" value="217.17.159.22"> 
                </form> 
                2 
            </td> 
            <td> 
                209 
            </td> 
            <td> 
                <input type="text" id="nameg_209" value="BALA BAŞAK KAN"> 
            </td> 
            <td> 
                <input type="text" id="ipg_209" value="217.17.159.22"> 
            </td> 
            <td>
                <button type="button" name="Kaydet_209" class="searchButton" onclick="postData('myForm_209','209')">SAVE</button>
            </td>
        </tr> 
</tbody> 
</table> 
<script> 
function postData(formId,keyy){ 
    //alert(document.getElementById(formId).length);
    //alert(document.getElementById('name_'+keyy).value);
    document.getElementById('name_'+keyy).value=document.getElementById('nameg_'+keyy).value;
    document.getElementById('ip_'+keyy).value=document.getElementById('ipg_'+keyy).value;

    //alert(document.getElementById('name_'+keyy).value);
    document.getElementById(formId).submit(); 
}
</script> 
  • 1
    Hi and welcome to S/O - and thank you for actively contributing! :) Please consider expanding on your answer. It's helpful to provide context around an answer, instead of only code. It is also worth noting that this question was asked 2009 :) [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) is well worth reading! – CmdrSharp Apr 04 '20 at 21:40