在MVC中编辑可变长度的项目列表

时间:2009-07-08 08:52:38

标签: jquery asp.net-mvc

我正在开发一个MVC Web应用程序,并且要求有一个可变长度的项目列表。用户应该能够添加/编辑和删除行,并在所有行上执行批量更新。

我开始从两篇博文开始工作,这些博文几乎涵盖了大部分工作,所以全部归功于史蒂夫桑德森。

Editing a variable-length list of items in ASP.NET MVC

我的观点如下

<% using (Html.BeginForm()) { %>

<div id="placeholder">
    <% for (int i = 0; i < Model.Count(); i++)
       {
           ViewData["index"] = i;
           Html.RenderPartial("ProfileItemLine", Model.ElementAt(i), new ViewDataDictionary(ViewData) {
            {"prefix", "items"}
        });
       } 
    %>
</div>

<div id="addProfileItem">
    <a href="" id="addItem">Add another item</a>
</div>

<input type="submit" value="Save changes" />

<% } %>

使用jQuery处理添加和删除

    $(document).ready(function() {

    var nextIndex = <%=ViewData.Model.Count()%>;
    setRemoveLinks();

    $('#addItem').click(function() {
        var action = '/Profile/BlankItemLine?index=' + nextIndex;
        $.get(action, 'html', function(lineItemHtml) {
            $('#placeholder').append(lineItemHtml);
            setRemoveLinks();
        });
        nextIndex++;
        return false;
    });
});

function setRemoveLinks() {
    $('a.removeItem').click(function() {
        $(this).parent('div').remove();
        return false;
    });
}

ProfileItemLine ViewUserControl如下所示减去格式和纯文本

<div>
<% var fieldPrefix = string.Format("{0}[{1}].", ViewData["prefix"], ViewData.Model.Sequence); %>
<%= Html.Hidden(fieldPrefix + "ProfileItemId", ViewData.Model.ProfileItemId)%>
<%= Html.TextBox(fieldPrefix + "Title", ViewData.Model.Title, new { size = "30"})%>
<%= Html.CheckBox(fieldPrefix + "IsHighlighted", ViewData.Model.IsHighlighted)%>   
<a href="" class="removeItem">Delete</a></div>

到目前为止,这个列表正确地绑定到了模型,只要我只添加它也能正常工作。

问题与删除有关。删除工作并删除正确的行但我丢失了表单提交上的所有绑定。在Steve的帖子中,他提到RC已经改变了模型绑定的工作方式,并且它要求所有索引都处于不间断的升序中。

史蒂夫列出了一些代码来实现工作,其中涉及在表单提交上重新排序列表,但它在“var controls =”行引发异常,方法不受支持。

$(function() {
$("form").submit(function() {
    // Normalize the sequence before submitting the form
    ensureControlGroupsInNumericalOrder("#placeholder div", "items");
});});

function ensureControlGroupsInNumericalOrder(groupSelector, controlNamePrefix) {
var groups = $(groupSelector);
var nameToEndOfIndexRegex = new RegExp(controlNamePrefix + "\\[\\d+");
for (var seq = 0; seq < groups.length; seq++) {
    var controls = $("*[name~=" + controlNamePrefix + "\[]", groups[seq]);
    for (var c = 0; c < controls.length; c++)
        controls[c].name = controls[c].name.replace(nameToEndOfIndexRegex, controlNamePrefix + "[" + seq);
}}

两次删除索引1和2后的html输出示例

    <div id="placeholder">
<div>
    <input id="items[0]_ProfileItemId" name="items[0].ProfileItemId" type="hidden" value="0fd3a3f5-907e-4eb1-8f69-26e3840e5e12" />
    <input id="items[0]_Title" name="items[0].Title" size="30" type="text" value="Number 1" />
    <input id="items[0]_IsHighlighted" name="items[0].IsHighlighted" type="checkbox" value="true" />
    <input name="items[0].IsHighlighted" type="hidden" value="false" />   
    <a href="" class="removeItem">Delete</a>  
</div>
<div>
    <input id="items[3]_ProfileItemId" name="items[3].ProfileItemId" type="hidden" value="0fa1a3f5-907e-4eb1-8f69-26e3840e5e12" />
    <input id="items[3]_Title" name="items[3].Title" size="30" type="text" value="Number 3" />
    <input id="items[3]_IsHighlighted" name="items[3].IsHighlighted" type="checkbox" value="true" />
    <input name="items[3].IsHighlighted" type="hidden" value="false" />   
    <a href="" class="removeItem">Delete</a>  
</div>
</div>

我在表单提交上模拟绑定到IEnumerable,在这个例子中,我只返回第一个项目而不是第二个项目,因为它是项目[3]而不是项目1

public ActionResult EditItems(Guid id, IEnumerable<ProfileItem> items)
{
     if (ModelState.IsValid)
     {
         // Save items
     }
     if (ModelState.IsValid)
         return RedirectToAction("Index");
     else
         return View(items);
 }

我仍然在研究jQuery和正则表达式,所以我想知道是否有人能指出我的解决方案。

提前致谢

1 个答案:

答案 0 :(得分:1)

为什么你需要单独的元素信息?

使用

是不是更明智
<div id="div1">

删除?

<a rel="1" id="item + item id (not per se 1 )" class="delete">delete</a>

所以你可以使用

$('.delete').bind('click',function(){ 
  $('#div' + $(this).attr('rel') ).remove();
  // plus delete call to db ?
});

这就是我经常做的事情:)

你可以在你的html创建循环中编写div和rel的编号,所以顺序总是正确的。