user1320304
user1320304

Reputation: 23

Dynamically add model row to table

I've read a bunch of articles now, from Phil Haacks "model binding to a list" to Steve Sanderson's "Editing a variable length list" and now trying to solve my problem - however I couln't really get it working.

I have two models - Order and Article. An order has many articles. The order view contains an articles table.

Currently, I'm creating the first table row using EditorFor(model => model.Articles) from within my Order View Model.

It recognizes that Articles is a list and returns the right list items. So far so good.

Now I want a link that adds an article to the table row but by using an AJAX Request to the Controller, which then returns a partial view (only containing the article table row). I already got that working using this tutorial: http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

However, my problem is that I don't know how i can continue the article row sequence in ASP.NET MVC "style", so that it will get recognized on submit. (e.g. Articles[1].Number Articles[2].Number etc.)

Here's my code. The "add article" link should add an article and send an ajax request to /orders/BlankArticleRow

public ActionResult BlankArticleRow(int pos)
        {
            Article article = new Article()
            {
                Position = pos
            };

            return View(article);
        }

The partial view for BlankArticleRow looks like this:

@model Bestellinterface.Models.Article

@{
    Layout = null;
}

@Html.EditorFor(model => model)

Works fine. When i click the "add article" link the row gets added, however the attributes of the text fields etc. do not have the right format. What i want is that it continues the numbering of the html elements, Articles[0].Number, Articles[1].Number, Articles[2].Number ...

Is that possible with EditorFor? Is there a way to simulate a list so that it will keep numbering?

Upvotes: 0

Views: 1431

Answers (2)

B Z
B Z

Reputation: 9453

I think you are missing the extension Steve created

If you look at the article it is used like this:

<% using(Html.BeginCollectionItem("gifts")) { %>
    Item: <%= Html.TextBoxFor(x => x.Name) %> 
    Value: $<%= Html.TextBoxFor(x => x.Price, new { size = 4 }) %> 
<% }

Upvotes: 0

Ben Foster
Ben Foster

Reputation: 34800

Yes you can use EditorFor for this:

    @{ int i = 0; }
@foreach (var article in Model.Articles)
{
@Html.EditorFor(model => Model.Articles[i])
i++;
}

Assuming the editor template contains fields Title, Description we would end up with Articles[i].Title, Articles[i].Description.

One solution for you may be to return a partial containing all the Articles for the Order which would then ensure your indexes are correct.

Alternatively you can update the indexes of your inputs with javascript.

To keep the indexes correct when removing items from a dynamic table I wrote the following:

//reset index values
$('#links-table tbody tr').each(function (index, value) {
    $(this).find('input[type=text]').prop('name', function (i, e) { return e.replace(/(\d+)/g, index) });
});

This looks for the index in each input's name e.g. Articles[2].Title and replaces it with the new index. You could potentially do something similar on the success of your ajax call.

Hope that helps Ben

Upvotes: 2

Related Questions