MVC3 Razor - Editing a variable length list

别说谁变了你拦得住时间么 提交于 2019-12-24 06:47:22

问题


I followed Steven Sanderson's blog - http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

When I try to add another row of items, rather than adding the row it sends me to the url with the returned partial view.

How do I prevent this from happening and hence add an actual row?

My code below along with the path (as I am using Areas):

MyWebUI

Areas/Client/MyMoveItems/Index.cshtml

@model IEnumerable<MovinMyStuff.Domain.Entities.MoveItem>
@using MovinMyStuff.WebUI.HtmlHelpers

@{
ViewBag.Title = "Index";
}

<h1>My Move Items</h1>
@using (Html.BeginForm())
{
<table class="move-item">
    <tr>
        <th>
            Item
        </th>
        <th class="dimension-header">
            L
        </th>
        <th class="dimension-header">
            W
        </th>
        <th class="dimension-header">
            H
        </th>
        <th class="weight-header">
            Wt
        </th>
        <th class="qty-header">
            Qty
        </th>
        <th>
            Addt'l Work
        </th>
    </tr>
    <tr>
        <td colspan="7">
            <div id="editorRows">
                @foreach (var item in Model)
                {
                    Html.RenderPartial("_MoveItemEditorRow", item);
                }
            </div>
        </td>
    </tr>
</table>
@Html.ActionLink("Add Item", "Add", new { area = "Client" }, new { id = "addItem" })
<input type="submit" value="Finished" />
}

Areas/Client/MyMoveItems/_MoveItemEditorRow.cshtml

@model MovinMyStuff.Domain.Entities.MoveItem
@using MovinMyStuff.WebUI.HtmlHelpers

@using (Html.BeginCollectionItem("moveitems"))
{
    <div class="editorRow">
<tr>
    <td class="item-name">
        @Html.TextBoxFor(model => model.MoveItemType)
        @Html.ValidationMessageFor(model => model.MoveItemType)
</td>
<td class="item-dimension">
    @Html.EditorFor(model => model.Length)
    @Html.ValidationMessageFor(model => model.Length)
</td>
<td class="item-dimension">
    @Html.EditorFor(model => model.Width)
    @Html.ValidationMessageFor(model => model.Width)
</td>
<td class="item-dimension">
    @Html.EditorFor(model => model.Height)
    @Html.ValidationMessageFor(model => model.Height)
</td>
<td class="item-weight">
        @Html.EditorFor(model => model.Weight)
        @Html.ValidationMessageFor(model => model.Weight)
</td>
<td class="item-qty">
        @Html.EditorFor(model => model.Quantity)
        @Html.ValidationMessageFor(model => model.Quantity)
</td>
<td class="work-items-group">
    <table class="work-items">
        <tr>
            <td>Assembly</td>
            <td>
            @Html.EditorFor(model => model.Assemble)
            @Html.ValidationMessageFor(model => model.Assemble)
            </td>
        </tr>
    </table>
    <table class="work-items">
        <tr>
            <td>Glass</td>
            <td>
            @Html.EditorFor(model => model.HasGlass)
            @Html.ValidationMessageFor(model => model.HasGlass)
            </td>
        </tr>
    </table>
</td>
</tr>
</div>
}

Areas/Client/Controllers/MyMoveItemsControllers.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MovinMyStuff.Domain.Entities;
using MovinMyStuff.Domain.Concrete;

namespace MovinMyStuff.WebUI.Areas.Client.Controllers
{ 
public class MyMoveItemsController : Controller
    {
    private EFDbContext db = new EFDbContext();

    //
    // GET: /Client/MyMoveItems/

    public ActionResult Index()
    {
        var moveitems = db.MoveItems.Include(m => m.Move);
        return View(moveitems);
    }

    [HttpPost]
    public ActionResult Index(IEnumerable<MoveItem> moveitems)
    {
        return View("Completed", moveitems);
    }

    public PartialViewResult Add()
    {
        return PartialView("_MoveItemEditorRow", new MoveItem());
    }
}
}

HtmlHelpers/HtmlPrefixScopeExtension.cs

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;

namespace MovinMyStuff.WebUI.HtmlHelpers
{
public static class HtmlPrefixScopeExtensions
{
    private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";

    public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
    {
        var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
        string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();

        // autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
        html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));

        return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
    }

    public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
    {
        return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
    }

    private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
    {
        // We need to use the same sequence of IDs following a server-side validation failure,  
        // otherwise the framework won't render the validation error messages next to each item.
        string key = idsToReuseKey + collectionName;
        var queue = (Queue<string>)httpContext.Items[key];
        if (queue == null) {
            httpContext.Items[key] = queue = new Queue<string>();
            var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
            if (!string.IsNullOrEmpty(previouslyUsedIds))
                foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
                    queue.Enqueue(previouslyUsedId);
        }
        return queue;
    }

    private class HtmlFieldPrefixScope : IDisposable
    {
        private readonly TemplateInfo templateInfo;
        private readonly string previousHtmlFieldPrefix;

        public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
        {
            this.templateInfo = templateInfo;

            previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
            templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
        }

        public void Dispose()
        {
            templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
        }
    }
}
}

Scripts/mms-custom.js

$("#addItem").click(function () {
$.ajax({
    url: this.href,
    cache: false,
    success: function (html) { $("#editorRows").append(html); }
});
return false;
});

$("a.deleteRow").live("click", function () {
$(this).parents("div.editorRow:first").remove();
return false;
});

Views/Shared/_ClientLayout.cshtml

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.5.1.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/modernizr-2.5.3.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/mms-custom.js")" type="text/javascript"></script>
@(Html.Telerik().StyleSheetRegistrar()
    .DefaultGroup(group => group.Add("telerik.common.css")
                                .Add("telerik.default.css"))
)
</head>
<body>
    <section>
    @RenderBody()
</section>
</body>
</html>

回答1:


Try this:

First: Make sure your jQuery code (Scripts/mms-custom.js) is inside $(document.ready -- it does not look like it is if that is if you posted your entire file above.

If that doesn't fix it by itself, try this:

Second:

$("#addItem").click(function () {
    $.ajax({
        url: this.href,
        cache: false,
        success: function (data) { $("#editorRows").append(data);  return false;}
    });
    return false;
});

in place of your code:

$("#addItem").click(function () {
$.ajax({
    url: this.href,
    cache: false,
    success: function (html) { $("#editorRows").append(html); }
});
return 

I had a similar problem when using that blog post as a point of reference.



来源:https://stackoverflow.com/questions/11387036/mvc3-razor-editing-a-variable-length-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!