views:

697

answers:

4

Hi,

I need to be able to edit a table of data in the browser.

I have seen in MVCContrib there is a HTML helper to render out a table. Useful... but what about if I want the user to be able to edit that table? From what I can see it does not help there.

What is the best way to approach this?

Traditional FORM with a TABLE inside? If so is MVC smart enough to parse the posted data back into a collection of rows? How would that work anyway?

Or perhaps it should just switch to edit mode when a row is clicked (using javascript etc) then when user moves to a different row an AJAX action is called to submit just the one row. I can imagine the logic could get complex here - this would presumably still use a form but would I have to insert it into the DOM dynamically?

I also need to be able to add rows to this table. I do not require paging support.

Is there an off the shelf solution out there?

Should I go back to web forms? :)

+2  A: 

Take a look at Phil Haack's blog where he describes how to model bind to a list.

Maybe this can help?

BengtBe
interesting article. shows potential but claims to be out of date. also this is a low level solution - i was hoping for something more shrink wrapped
Schneider
How about this solution using jQGrid:http://ericdotnet.wordpress.com/2009/05/02/editing-in-jqgrid-with-aspnet-mvc/
BengtBe
ill accept this as the answer as its as far as I got. My mistake was thinking anything UI of sophistication could be accomplished on the web that was not a hack! HTML was never meant for this...
Schneider
+1  A: 

I would checkout one of the javascript UI libraries first:

WebForms are easier when it comes to quickly developing rich UI's like editable grids.

Todd Smith
Thanks.Flexigrid does not appear to support editing yet.Yahoo DataTable looks basic which is fine, but I can't see how you save data back.ExtJs - I just discovered this. Looks good (*too* complex?). Investigating now
Schneider
A: 

Last night I implemented a simple solution: form + table inside, using input fields in the cells with naming convention as described in Phil Haack's blog (thanks to @BengtBe for link).

It's working but its a bit fiddly (e.g. adding rows with jquery requires me to work out the next unused index).

So I am still looking for more solutions.

One I have discovered is the extjs library which provides a very rich grid. I have yet to work out whether there is an easy way to post back the grid data to one of my controller actions yet though...

Schneider
+1  A: 

Hello,
I've got the same problem, and I have found a solution for it. Don't think it's the most beautiful, but it's ideal for me, because one of my requirements was be able to edit table data using jQuery's Jeditable plugin.

So I generate a table using MVCContrib's Grid<> extension:

Html.Grid<Somenamespace.Line>( Model.InvoiceLines )
           .Attributes( id => "InvoiceGrid" )
           .Columns( column => {
               column.For( li => li.LineItem.ItemDescription ).Attributes( name => ".LineItem.ItemDescription", @class => "click" );
               column.For( li => li.LineItem.InvoiceUnitNetPrice ).Named( "Unit net price " ).Attributes( name => ".LineItem.InvoiceUnitNetPrice", @class => "click" );
               column.For( li => li.LineItem.InvoiceQuantity ).Attributes( name => ".LineItem.InvoiceQuantity", @class => "click" );
           })
           .Render();  
//rest of the code
Html.Submit("_submit", "Save");

Right now You can edit in place values, but it doesn't upgrade corresponding model. All the magic happens after user clicks submit button:

$(document).ready(function() {
        $('#_submit').click(function(e) {
                e.preventDefault();
                $('#InvoiceGrid tbody tr').each(function(index) {
                    var hidden = $('<input />').attr({ type: 'hidden', name: 'InvoiceLines.Index', value: index });
                    $(this).children('td:first-child').before(hidden);
                    $(this).children('td:not(:first-child)').each(function() {
                        $(this).append($('<input />').attr({ type: 'hidden', value: $(this).text(), name: 'InvoiceLines[' + index + ']' + $(this).attr('name') }));
                    });
                });
                $('form').submit();
            });

            //editable stuff            
            $('.click').editable(function(value, settings) {
                return (value);
            }, { submit: 'OK' });
        });

In every TD I create hidden input, with value from that TD, in every row input with Index, and the most important here is 'name' attribute: Name of collection in Model[here goes index].rest.of.path, so in this particular case (example):

InvoiceLines[2].LineItem.ItemDescription

Hope it'll help, because rich grid isn't always an answer ;)

Regards Mateusz

matma