简体   繁体   中英

How to align form fields within a table for inline editing?

I am developing a webapp using Spring, jsp, javascript, jquery.

I display a table using datatables. When I click on a table row I want it to change all fields to an inline edit inputs, selects etc. In addition I want to show some extra input fields in the next row and a save button.

Now I see several ways of doing this. I am not sure which one to take.

  1. I can get a handle to selected row and then iterate over the td and transform them to input/select fields. I can then insert an extra row for the new fields and the save button. I don't see this as a clean solution. I will have to issue a Post manually instead of using the Spring ModelAttribute binding for the form. (Can I still use ModelAttribute here?)

  2. I can create an edit form in a jsp file which looks like:

    <form:form action="" commandName=""> <td> <input ... > </td> <td> <select ... > </td> </tr> <tr> <td> <label> <input new field> </td> <td> <button> </td> </tr>

Note I do not have a beginning in a jsp file as I plan to reuse the tr from the existing row in the table. This way I would be able to have a clean form and also use the update method I have already written which binds the form to a Java class. Also I do not have to bother about the alignment of input fields with the column names.

The generated html looks like ...

The problem with this approach is the placement of form element in the html causes the entire form to be cramped into one cell of the table which does not look good and messes up the whole layout. Is there a way out? Should I just replace the contents of the table with a having a colspan and then put divs inside this element and fine tune the css to ensure that the input fields align with the column names in the table?

显示错误对齐的图像

Is there a better solution you can suggest? In case the question is not very clear I can fill in more details.

This is what I would do (coming from a server-side development background, as I know developers love easy solutions)

  1. Wrap the table with a single form
  2. on Edit row (clicking row) open an ajax request that returns pure html that looks like the exact tr, only with whatever extra you want to include:

<tr><td><input type="text" name="text1" ... /></td><td>second row... </td></tr>
<tr><td colspan="2">And hey, here is more, and the save button ... </td></tr>  

  1. in jQuery replace tr with content retrieved (myTr.replace($(ajaxResponse))) or something similar

  2. now Save button is a regular submit for the form

  3. if you want to submit via ajax, once done, return the old html in your ajax response and replace the two trs with the old tr (you just need to hook it by giving new trs an attribute that you can find easily in jquery)

  4. don't forget to switch off a global key to prevent double editing, users can edit one row at a time


Update: adding a second solution to dump load on client instead of server

To avoid overloading the server (though I wouldn't be worried about it until it becomes a regular habit), you can make your form fields as a template inside your HTML and use string replacement (or jQuery Templates), so instead of ajaxing to get response in step 2, you call the template, and replace the strings with attributes you save in every row... like this:

<div id="myTemplate"> // or you can use jQuery script templates
    <tr><td><input type="text" name="${Name}" ... /> id is ${Id}</td><td>${SecondRow}... </td></tr>
    <tr><td colspan="2">Save button here.... and may be more text ${MoreText}</td></tr>  
</div>

in every row in your code add sufficient attributes or ids to know what you want to replace with, like this:

<tr data-itemid="34"><td ><input type="text" name="text1" id="findme" ... /></td><td data-moretext="here is more text">second column </td></tr>...etc

so now in your replacement script:

$("#myTemplate").html().replace("${Name}", $(thisrow).find("#findme").attr("name"))
    .replace("${Id}",$(thisrow).attr("data-itemid"));

etc...

Of course after submission it has to be a to server, but in case user "cancels" you can have another readonly template

By the way, that is the way I usually go with, I use jQuery templates, and create edit and view templates, but I also repeat edit forms and I use jQuery ajax submit manually... but that... my friend, is not a simple clean and maintainable solution I'm afraid

I've been into an issue like this a year before. This is a messy problem. Either way if you traverse each td of row and convert it into text field or You can create a separate jsp file for this.

But the best in this case is to change the content of td to input field and post the data manually. because in this case you cannot wrap form tag around tr. You have to manually post the values of each input field.

PS The very best solution is to create an edit dialog.

There is another solution, but I'm under the impression you won't like it very much... you can use a single form for the whole datatable (wrapping the whole table in a form is permitted) generate input fields for the current row and if it's updated submit the form asyncronously with javascript and restore td contents to the original html, if you name your fields such as name="field[]" you can also submit multiple rows at a time (I don't know if you'd want that though).

You can write html code such as

<form action="">
<table>
<tr><td><input type="hidden" name="row[]" value="1"/><input name="field[]"/></td></tr>
<tr><td>field value for row2</td></tr>
<tr><td><input type="hidden" name="row[]" value="3"/><input name="field[]"/></td></tr>
</table>
</form>

you can just grab the form with jquery and submit it via xmlhttprequest as I suspect you would if each row was a separate form (which is illegal), if you don't want multiple rows, just remove the [] and submit each row and upon submitting the values you get them numbered correctly, don't know exactly how it would behave in java but in php I'd get the following:

$_GET[row][0] = 1;
$_GET[field][0] = 'value typed in row1';
$_GET[row][1] = 3;
$_GET[field][1] = 'value typed in row3';

Alternative table definition to avoid having the same name again

<form action="">
<table>
<tr><td><input name="field[1]"/></td></tr>
<tr><td>field value for row2</td></tr>
<tr><td><input name="field[3]"/></td></tr>
</table>
</form>

It's the same table as above only you set explicit indexes for each entry thus avoiding duplicate names in the response, preferrably use a unique identifier which can describe the row from the table that you're modifying in there (when possible I use the primary key) instead of the row number, just in case that wasn't clear enough.

Have you tried:

  1. Wrap whole table in the form
  2. have the data entries as disabled inputs with their borders hidden via CSS
  3. when user clicks edit, enable the inputs and show the borders
  4. You'll probably need hidden elements for each field
  5. When user submits the form, post via ajax and set the inputs back to disabled with hidden borders

What about contenteditable ?

Demo: http://jsfiddle.net/SO_AMK/XQekC/

jQuery:

var ctrlDown = false;
$(document).keydown(function(e) {
    if (e.which = "ctrlKey") {
        ctrlDown = true;
    }
}).keyup(function(e) {
    if (e.which = "ctrlKey") {
        ctrlDown = false;
    }
});


$('#example').dataTable();

$("#example tr").click(function() {
    if ($(this).hasClass("row_selected") && ctrlDown) {
        submitRow($(this));
        return false; // Break out so the next if doesn't run
    }
    else if ($(this).hasClass("row_selected") && ctrlDown == false) {
        return false; // Break out so the next if doesn't run
    }

    if ($(this).siblings(".row_selected").length && ctrlDown == false) {
        $(this).siblings(".row_selected").each(function() {
            submitRow($(this));
        });
    }

    $(this).addClass("row_selected");
    $(this).children("td").each(function() {
        $(this).attr("contenteditable", true);
    });
});

function submitRow(elm) {
    var data = [];
    $(elm).removeClass("row_selected").children("td").each(function() {
        data.push($(this).text());
    });
    alert(data); // This will stop the keyup from firing, but you won't (I hope) really be using alerts
}​

This has everything but a submit-to-server function, it's also completely inline and has support for selecting multiple rows.

The only bug is, when it shows the data alert the focus goes off of the main window so the keyup event never fires, since you probably won't be using alerts this shouldn't be an issue. To fix it in the fiddle, press and release ctrl after the alert closes before clicking a row.

I see couple of problems

  1. Your no. Of columns in the table & the edit columns you show are different
  2. You might not be having complete data to edit the row so you might need to do an Ajax call and get it

If you have complete data on then you don't need point 2, let's assume you have a function f called with the clicked tr as the parameter

function f(row)
{
     var newRow = yourTable.insertRow(parseInt(row.rowIndex,10)+1);
     //you can place the above or below the clicked row , or you can even make the row visible false And then show the new row
     Var newCell = newRow.insertCell(0);
     newCell.colspan = 6;//the count if columns in your table row
     NewCell.innerHTML = " put your HTML content here";
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM