How to handle multiple <form>s in a single table and have HTML validate
Asked Answered
D

4

10

It seems that I cannot have two forms embedded into a single table AND have my HTML validate. For example, the W3 Validator gives me

Element <form> not allowed as child of element <tr> in this context.

I don't see a way to go around validation errors.

What I want to achieve is this:

  • In an HTML table "row" I have and can change some input values and then use my "Save" button at the end of the row, to save them
  • If I have to delete a row, I can do so by pressing Delete button.
  • UI-wise it makes sense to me to have two forms, one each for Save/Delete button, per row.
  • I can have several rows, each row with its own Save/Delete button

Example UI

Numbers are input fields and save/delete are buttons. enter image description here

My simplified non-conforming HTML below:

<!DOCTYPE html>
<html>
<head>
<title>HTML</title>
</head>
<body>
<table>

<tr>
    <form>
    <td><input type="text" name="row_id" value="1"></td>
    <td><input type="text" name="five" value="5"></td>
    <td><input type="text" name="three" value="3"></td>
    <td><input type="submit" value="Save This Row"></td>
    </form>

    <td><form>
            <input type="text" name="row_id" value="1">
            <input type="submit" value="Delete This Row">
    </form></td>
</tr>
</table>

</body>
</html>

HTML works surprisingly, but it does not validate. I am seeking a solution where it does both - work and validate.

Downandout answered 25/11, 2014 at 21:30 Comment(0)
L
7

You have several options:

  1. Keep your code as is. It’s invalid, but it works. It might fail in some future browsers, but that’s not probable.
  2. Reorganize the code so that all fields are in one form and put the entire table inside that form. This probably requires changes to the server-side form handler and may require changes to HTML too.
  3. Reorganize it so that you have a two-column table, with the first column containing forms that contain inner one-row tables. This requires that you explicitly set the column widths of the inner tables to make the whole look like one table.
  4. Put the Save buttons in forms (inside the cell) and refer to those forms from the input buttons with the form attribute. This way each form would be inside one cell and it would be connected with input elements outside it with those attributes. This would be the cleanest solution, but the form attribute is not supported by IE.
Leucippus answered 25/11, 2014 at 22:51 Comment(0)
S
4

You can use the form attribute and place your form/input wherever you like.

form A string specifying the element with which the input is associated (that is, its form owner). This string's value, if present, must match the id of a element in the same document. If this attribute isn't specified, the element is associated with the nearest containing form, if any.

The form attribute lets you place an input anywhere in the document but have it included with a form elsewhere in the document.

Example:

<form action="/save" method="PATCH" id="patch"></form>
<form action="/delete" method="DELETE" id="delete"></form>

<table>
  <tbody>
    <tr>
      <td><input form="patch" name="row_id" value="1"></td>
      <td><input form="patch" name="five" value="5"></td>
      <td><input form="patch" name="three" value="3"></td>
      <td><input form="patch" type="submit" value="Save This Row"></td>
      <td>
        <input form="delete" name="row_id" value="1">
        <input form="delete" type="submit" value="Delete This Row">
      </td>
    </tr>
  </tbody>
</table>

you can also take advantage of the formaction and the formmethod attribute on the submit button for a more dynamic form

Schulze answered 16/7, 2020 at 11:27 Comment(1)
This is the cleanest option IMO. It allows a complete disassociation of forms from the html layout, including having multiple forms interlaced with one another (IE every other field could be for a different form).Dispirit
R
2

Another solution to this problem is to post arrays of textboxes, and an ID for the row you wish to SAVE or DELETE.

Something similar to:

<form>
  <table>
    <tr>
      <td><input type="text" name="row_id[1]" value="1"></td>
      <td><input type="text" name="five[1]" value="5"></td>
      <td><input type="text" name="three[1]" value="3"></td>
      <td>
        <button name="action" type="submit" value="delete_1">Delete</button>
        <button name="action" type="submit" value="save_1">Save</button>
      </td>
    </tr>
    <tr>
      <td><input type="text" name="row_id[2]" value="2"></td>
      <td><input type="text" name="five[2]" value="7"></td>
      <td><input type="text" name="three[2]" value="10"></td>
      <td>
        <button name="action" type="submit" value="delete_2">Delete</button>
        <button name="action" type="submit" value="save_2">Save</button>
      </td>
    </tr>
  </table>
</form>

You can of course repeat the lines of the table as often as you wish. Each one has a unique ID which is contained within the action button value, as well as within the array of input fields. So if for example you click the Delete button on the second row, you would receive an ACTION value of "delete_2" at the server end. A quick split, explode or similar would then give you an ACTION and an ID.

For the save function, you can then just use this ID to call the relevant text fields from their relevant arrays.

This method will allow you to embed the entire table within a single form.

As a side point, as the DELETE function probably doesn't require the use of any other variables, as these will rarely be updated and then deleted in a single motion, you could achieve the same aim with a simple URL, and a GET parameter for the ID. Be careful here though, as you could allow your users to delete multiple records, just by changing the URL variables, and recalling the page over and over.

Rennin answered 30/8, 2017 at 15:33 Comment(0)
S
0

Similarly to reorganizing your code as Jukka suggestions, you can have the entire table inside one form, but add two additional forms (outside the table) with only hidden fields (one form for save, and one form for delete). The buttons on the large form would not submit that form. Instead they would populate the hidden form fields with the values from that row, and then submit the hidden form. This requires some JavaScript, but unlike Jukka's suggestion, no server-side changes would be necessary.

Shenika answered 8/12, 2014 at 18:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.