MVC3剃刀 - 编辑可变长度列表剃刀、长度、编辑、列表

2023-09-10 21:03:41 作者:空心人

我跟史蒂芬·桑德森的博客 - 的http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

当我尝试添加的项目另一行,而不是增加其发送我行的网址与返回的局部视图。

如何发生,从而增加了实际的行吗?我prevent这种

随着路径下我的code(因为我使用的领域):

MyWebUI

地区/客户/ MyMoveItems / Index.cshtml

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

@ {
ViewBag.Title =指数;
}

< H1>我的移动项目< / H1>
@using(Html.BeginForm())
{
<表类=移动项目>
    &其中; TR>
        <第i个
            项目
        < /第i个
        百分位类=维头>
            大号
        < /第i个
        百分位类=维头>
            W¯¯
        < /第i个
        百分位类=维头>
            H
        < /第i个
        百分位类=重头>
            重量
        < /第i个
        百分位类=数量头>
            数量
        < /第i个
        <第i个
            Addt'l工作
        < /第i个
    < / TR>
    &其中; TR>
        < TD合并单元格=7>
            < D​​IV ID =editorRows>
                @foreach(以模型的VaR项)
                {
                    Html.RenderPartial(_ MoveItemEditorRow,项目);
                }
            < / DIV>
        < / TD>
    < / TR>
< /表>
@ Html.ActionLink(添加项目,添加,新{面积=客户},{新的id =的addItem})
<输入类型=提交值=完成/>
}
 

地区/客户/ MyMoveItems / _MoveItemEditorRow.cshtml

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

@using(Html.BeginCollectionItem(moveitems))
{
    < D​​IV CLASS =editorRow>
&其中; TR>
    < TD类=项目名称>
        @ Html.TextBoxFor(型号=> model.MoveItemType)
        @ Html.ValidationMessageFor(型号=> model.MoveItemType)
< / TD>
< TD类=项维>
    @ Html.EditorFor(型号=> model.Length)
    @ Html.ValidationMessageFor(型号=> model.Length)
< / TD>
< TD类=项维>
    @ Html.EditorFor(型号=> model.Width)
    @ Html.ValidationMessageFor(型号=> model.Width)
< / TD>
< TD类=项维>
    @ Html.EditorFor(型号=> model.Height)
    @ Html.ValidationMessageFor(型号=> model.Height)
< / TD>
< TD类=项重>
        @ Html.EditorFor(型号=> model.Weight)
        @ Html.ValidationMessageFor(型号=> model.Weight)
< / TD>
< TD类=项目,数量>
        @ Html.EditorFor(型号=> model.Quantity)
        @ Html.ValidationMessageFor(型号=> model.Quantity)
< / TD>
< TD类=工作项目组>
    <表类=工作项目>
        &其中; TR>
            < TD>大会< / TD>
            < TD>
            @ Html.EditorFor(型号=> model.Assemble)
            @ Html.ValidationMessageFor(型号=> model.Assemble)
            < / TD>
        < / TR>
    < /表>
    <表类=工作项目>
        &其中; TR>
            < TD>玻璃和LT; / TD>
            < TD>
            @ Html.EditorFor(型号=> model.HasGlass)
            @ Html.ValidationMessageFor(型号=> model.HasGlass)
            < / TD>
        < / TR>
    < /表>
< / TD>
< / TR>
< / DIV>
}
 
pr工具有几个 是不是只有剃刀那几个

地区/客户机/控制器/ MyMoveItemsControllers.cs

 使用系统;
使用System.Collections.Generic;
使用System.Data这;
使用System.Data.Entity的;
使用System.Linq的;
使用的System.Web;
使用System.Web.Mvc;
使用MovinMyStuff.Domain.Entities;
使用MovinMyStuff.Domain.Concrete;

命名空间MovinMyStuff.WebUI.Areas.Client.Controllers
{
公共类MyMoveItemsController:控制器
    {
    私人EFDbContext DB =新EFDbContext();

    //
    // GET:/客户/ MyMoveItems /

    公众的ActionResult指数()
    {
        变种moveitems = db.MoveItems.Include(米=> m.Move);
        返回查看(moveitems);
    }

    [HttpPost]
    公众的ActionResult指数(IEnumerable的<移动选项> moveitems)
    {
        返回视图(已完成,moveitems);
    }

    公共PartialViewResult的Add()
    {
        返回PartialView(_ MoveItemEditorRow,新移动选项());
    }
}
}
 

HtmlHelpers / HTML prefixScopeExtension.cs

 使用系统;
使用System.Collections.Generic;
使用的System.Web;
使用System.Web.Mvc;

命名空间MovinMyStuff.WebUI.HtmlHelpers
{
公共静态HTML类prefixScopeExtensions
{
    私人常量字符串idsToReuseKey =__html prefixScopeExtensions_IdsToReuse_;

    公共静态IDisposable的BeginCollectionItem(这HtmlHelper的HTML,串集合名)
    {
        VAR idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext,集合名);
        字符串的ItemIndex = idsToReuse.Count> 0? 。idsToReuse.Dequeue():Guid.NewGuid()的ToString();

        //自动完成=关是需要解决一个非常恼人的Chrome浏览器的行为由此重用旧值用户点击后退,这将导致xyz.index和XYZ后[...]值不同步。
        html.ViewContext.Writer.WriteLine(的String.Format(<输入类型= \隐藏\名称= \{0} .index \自动完成= \关\的价值= \{1} \ />中,集合名,html.En code(的ItemIndex)));

        返回BeginHtmlField prefixScope(HTML,的String.Format({0} {1}],集合名,的ItemIndex));
    }

    公共静态IDisposable的BeginHtmlField prefixScope(这HtmlHelper的HTML,串htmlField preFIX)
    {
        返回新HtmlField prefixScope(html.ViewData.TemplateInfo,htmlField preFIX);
    }

    私有静态队列<字符串> GetIdsToReuse(HttpContextBase HttpContext的,串集合名)
    {
        //我们需要使用下面的服务器端验证失败的ID相同的序列,
        //否则框架将不会呈现验证错误消息每个项目旁边。
        字符串键= idsToReuseKey +集合名;
        VAR队列=(队列<字符串>)httpContext.Items [关键];
        如果(队列== NULL){
            httpContext.Items [关键] =队列=新问答LT;字符串>();
            VAR previouslyUsedIds = httpContext.Request [集合名+.index];
            如果(!string.IsNullOrEmpty(previouslyUsedIds))
                的foreach($ p中$ pviouslyUsedIds.Split字符串previouslyUsedId(,))
                    queue.Enqueue(previouslyUsedId);
        }
        返回队列;
    }

    私有类HtmlField prefixScope:IDisposable的
    {
        私人只读TemplateInfo templateInfo;
        私人只读字符串previousHtmlField preFIX;

        公共HtmlField prefixScope(TemplateInfo templateInfo,串htmlField preFIX)
        {
            this.templateInfo = templateInfo;

            previousHtmlField preFIX = templateInfo.HtmlField preFIX;
            templateInfo.HtmlField preFIX = htmlField preFIX;
        }

        公共无效的Dispose()
        {
            templateInfo.HtmlField preFIX = previousHtmlField preFIX;
        }
    }
}
}
 

脚本/ MMS-custom.js

  $(#的addItem)。点击(函数(){
$阿贾克斯({
    网址:this.href,
    缓存:假的,
    成功:函数(HTML){$(#editorRows)追加(HTML)。 }
});
返回false;
});

$(a.deleteRow)。生活(点击,函数(){
$(本)。家长(div.editorRow:第一),删除();
返回false;
});
 

查看/共享/ _ClientLayout.cshtml

 <!DOCTYPE HTML>
< HTML>
< HEAD>
<元字符集=utf-8/>
<冠军> @ ViewBag.Title< /标题>
<链接HREF =@ Url.Content(〜/内容/ Site.css)相对=样式类型=文本/ CSS/>
<脚本SRC =@ Url.Content(〜/脚本/ jQuery的-1.5.1.js)类型=文/ JavaScript的>< / SCRIPT>
<脚本SRC =@ Url.Content(〜/脚本/ MicrosoftAjax.js)类型=文/ JavaScript的>< / SCRIPT>
<脚本SRC =@ Url.Content(〜/脚本/ Modernizr的-2.5.3.min.js)类型=文/ JavaScript的>< / SCRIPT>
<脚本SRC =@ Url.Content(〜/脚本/ MMS-custom.js)类型=文/ JavaScript的>< / SCRIPT>
@(Html.Telerik()。StyleSheetRegistrar()
    .DefaultGroup(组=> group.Add(telerik.common.css)
                                。新增(telerik.default.css))
)
< /头>
<身体GT;
    &其中;节>
    @RenderBody()
< /节>
< /身体GT;
< / HTML>
 

解决方案

试试这个:

第一:确保您的jQuery code(脚本/ MMS-custom.js )里面 $(的document.ready - 它看起来并不像它如果是这样,如果你上面张贴整个文件

如果说本身并不解决它,试试这个:

二:

  $(#的addItem)。点击(函数(){
    $阿贾克斯({
        网址:this.href,
        缓存:假的,
        成功:功能(数据){$(#editorRows)追加(数据)。返回false;}
    });
    返回false;
});
 

代替你的code:

  $(#的addItem)。点击(函数(){
$阿贾克斯({
    网址:this.href,
    缓存:假的,
    成功:函数(HTML){$(#editorRows)追加(HTML)。 }
});
返回
 

我使用的博客文章作为参考点时,也有类似的问题。

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>

解决方案

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.

 
精彩推荐