在"MVC批量更新,可验证并解决集合元素不连续控制器接收不完全的问题"中,当点击"添加"按钮的时候,通过部分视图,在界面上添加新行。本篇体验使用jQuery Template,在界面上添加新行。

□ 思路

→引用jQuery Template所需要的js文件:jquery.tmpl.min.js
→在<script type="text/x-jquery-tmpl" id="movieTemplate"></script>中生成模版内容,里面包含占位符
→点击添加按钮的时候,把模版内容追加到界面上,并给占位符赋值

 

□ jQuery Template的内容大致是这样:

<script type="text/x-jquery-tmpl" id="movieTemplate">
<li style="padding-bottom:15px">
 
    <input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="${index}" />
 
    <img src="/Content/images/draggable-icon.png" style="cursor: move" alt=""/>
 
    <label>Title</label>
    <input name="FavouriteMovies[${index}].Title" type="text" value="" />
 
    <label>Rating</label>
    <input name="FavouriteMovies[${index}].Rating" type="text" value="0" />
 
    <a href="#" onclick="$(this).parent().remove();">Delete</a>
</li>
</script>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

为了得到以上内容,由帮助类方法获得:

    <script type="text/x-jquery-tmpl" id="movieTemplate">

            @Html.CollectionItemJQueryTemplate("MovieEntryEditor", new Movie())

    </script>

 

帮助类CollectionEditingHtmlExtensions:

模版内容同样是通过MovieEntryEditor.cshtml这个部分视图生成的,只不过生成的内容中包含了占位符。

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
 
namespace VariableCollection.Extension
{
    public static class CollectionEditingHtmlExtensions
    {
        /// <summary>
        /// 目标是生成如下格式
        ///<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="6d85a95b-1dee-4175-bfae-73fad6a3763b" />
        ///<label>Title</label>
        ///<input class="text-box single-line" name="FavouriteMovies[6d85a95b-1dee-4175-bfae-73fad6a3763b].Title" type="text" value="Movie 1" />
        ///<span class="field-validation-valid"></span>
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="html"></param>
        /// <param name="collectionName">集合属性的名称</param>
        /// <returns></returns>
        public static IDisposable BeginCollectionItem<TModel>(this HtmlHelper<TModel> html, string collectionName)
        {
            if (string.IsNullOrEmpty(collectionName))
            {
                throw new ArgumentException("collectionName is null or empty","collectionName");
            }
            string collectionIndexFieldName = String.Format("{0}.Index", collectionName);//FavouriteMovies.Index
            string itemIndex = null;
            if (html.ViewData.ContainsKey(JQueryTemplatingEnabledKey))
            {
                itemIndex = "${index}";
            }
            else
            {
                itemIndex = GetCollectionItemIndex(collectionIndexFieldName);
            }
 
            //比如,FavouriteMovies[6d85a95b-1dee-4175-bfae-73fad6a3763b]
            string collectionItemName = string.Format("{0}[{1}]", collectionName, itemIndex);
 
            TagBuilder indexField = new TagBuilder("input");
            indexField.MergeAttributes(new Dictionary<string, string>() {
                { "name", String.Format("{0}.Index", collectionName) }, //name="FavouriteMovies.Index"
                { "value", itemIndex },//value="6d85a95b-1dee-4175-bfae-73fad6a3763b"
                { "type", "hidden" },
                { "autocomplete", "off" }
            });
            html.ViewContext.Writer.WriteLine(indexField.ToString(TagRenderMode.SelfClosing));
 
            return new CollectionItemNamePrefixScope(html.ViewData.TemplateInfo, collectionItemName);
        }
 
         private class CollectionItemNamePrefixScope : IDisposable
         {
             private readonly TemplateInfo _templateInfo;
             private readonly string _previousPrefix;
 
             public CollectionItemNamePrefixScope(TemplateInfo templateInfo, string collectionItemName)
             {
                 this._templateInfo = templateInfo;
                 _previousPrefix = templateInfo.HtmlFieldPrefix;
                 templateInfo.HtmlFieldPrefix = collectionItemName;
             }
 
             public void Dispose()
             {
                 _templateInfo.HtmlFieldPrefix = _previousPrefix;
             }
         }
 
        /// <summary>
        /// 以FavouriteMovies.Index为键,把Guid字符串存放在上下文中
        /// 如果是添加进入部分视图,就直接生成一个Guid字符串
        /// 如果是更新,为了保持和ModelState的一致,就遍历原先的Guid
        /// </summary>
        /// <param name="collectionIndexFieldName">FavouriteMovies.Index</param>
        /// <returns>返回Guid字符串</returns>
        private static string GetCollectionItemIndex(string collectionIndexFieldName)
        {
            Queue<string> previousIndices = (Queue<string>)HttpContext.Current.Items[collectionIndexFieldName];
            if (previousIndices == null)
            {
                HttpContext.Current.Items[collectionIndexFieldName] = previousIndices = new Queue<string>();
                string previousIndicesValues = HttpContext.Current.Request[collectionIndexFieldName];
                if (!string.IsNullOrWhiteSpace(previousIndicesValues))
                {
                    foreach (string index in previousIndicesValues.Split(','))
                    {
                        previousIndices.Enqueue(index);
                    }
                }
            }
            return previousIndices.Count > 0 ? previousIndices.Dequeue() : Guid.NewGuid().ToString();
        }
 
        private const string JQueryTemplatingEnabledKey = "__BeginCollectionItem_jQuery";
        public static MvcHtmlString CollectionItemJQueryTemplate<TModel, TCollectionItem>(this HtmlHelper<TModel> html,
                                                                                    string partialViewName,
                                                                                    TCollectionItem modelDefaultValues)
        {
            ViewDataDictionary<TCollectionItem> viewData = new ViewDataDictionary<TCollectionItem>(modelDefaultValues);
            viewData.Add(JQueryTemplatingEnabledKey, true);
            return html.Partial(partialViewName, modelDefaultValues, viewData);
        }
    }
}    
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

□ MovieEntryEditor.cshtm部分视图与上篇相同

@using VariableCollection.Extension
@model VariableCollection.Models.Movie
 
<li style="padding-bottom: 15px;">
    @using (Html.BeginCollectionItem("FavouriteMovies"))
    {
        <img src="@Url.Content("~/Content/images/draggable-icon.png")" style="cursor: move" alt=""/>
 
        @Html.LabelFor(model => model.Title)
        @Html.EditorFor(model => model.Title)
        @Html.ValidationMessageFor(model => model.Title)
 
        @Html.LabelFor(model => model.Rating)
        @Html.EditorFor(model => model.Rating)
        @Html.ValidationMessageFor(model => model.Rating)
 
        <a href="#" onclick=" $(this).parent().remove(); ">删除行</a>
    }
</li>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

□ HomeController

        public ActionResult EditJqueryTemplate()
        {
            return View(CurrentUser);
        }
 
        [HttpPost]
        public ActionResult EditJqueryTemplate(User user)
        {
            if (!this.ModelState.IsValid)
            {
                return View(user);
            }
            CurrentUser = user;
            return RedirectToAction("Display");
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

□ EditJqueryTemplate.cshtml完整代码如下:

@using VariableCollection.Extension
@using VariableCollection.Models
@model VariableCollection.Models.User
 
@{
    ViewBag.Title = "EditJqueryTemplate";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
<h2>EditJqueryTemplate</h2>
 
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>最喜欢看的电影</legend>
        @Html.HiddenFor(model => model.Id)
        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
    </fieldset>
    
    <fieldset>
        <legend>最喜欢看的电影</legend>
        @if (Model.FavouriteMovies == null || Model.FavouriteMovies.Count == 0)
        {
            <p>没有喜欢看的电影~~</p>
        }
        <ul id="movieEditor" style="list-style-type: none">
            @if (Model.FavouriteMovies != null)
            {
                foreach (Movie movie in Model.FavouriteMovies)
                {
                    Html.RenderPartial("MovieEntryEditor", movie);
                }
            }
        </ul>
               
        <a id="addAnother" href="#" >添加</a>
    </fieldset>
    <p>
        <input type="submit" value="提交" />
    </p>
}
 
@section scripts
{
    <script src="~/Scripts/jquery.tmpl.min.js"></script>
    
    <script type="text/x-jquery-tmpl" id="movieTemplate">
            @Html.CollectionItemJQueryTemplate("MovieEntryEditor", new Movie())
    </script>
 
    <script type="text/javascript">
            $(function () {
                $("#movieEditor").sortable();
 
                $('#addAnother').click(function() {
                    viewModel.addNew();
                });
            });
 
            var viewModel = {
                addNew: function () {
                    $("#movieEditor").append($("#movieTemplate").tmpl({ index: viewModel._generateGuid() }));
                },
 
                _generateGuid: function () {
                    // Source: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/105074#105074
                    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
                        return v.toString(16);
                    });
                }
            };
    </script>
}
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

参考资料:

Editing Variable Length Reorderable Collections in ASP.NET MVC – Part 2: jQuery Templates

MVC批量更新,使用jQuery Template的更多相关文章

  1. MVC批量更新,可验证并解决集合元素不连续控制器接收不完全的问题

    在"MVC批量添加,增加一条记录的同时添加N条集合属性所对应的个体"中,有2个问题待解决: 1.由jquery动态生成了表单元素,但不能实施验证. 2.一旦集合元素不连续,控制器就 ...

  2. Spring批量更新batchUpdate提交和Hibernate批量更新executeUpdate

    1:先看hibernate的批量更新处理. 版本背景:hibernate 5.0.8 applicationContext.xml 配置清单: <?xml version="1.0&q ...

  3. EF结合SqlBulkCopy实现高效的批量数据插入 |EF插件EntityFramework.Extended实现批量更新和删除

    原文链接:http://blog.csdn.net/fanbin168/article/details/51485969   批量插入 (17597条数据批量插入耗时1.7秒)   using Sys ...

  4. mongodb 批量更新 数组的键操作的文件

    persons该文件的数据如下面的: > db.persons.find() { "_id" : 2, "name" : 2 } { "_id& ...

  5. mongodb批量更新操作文档的数组键

    persons文档的数据如下: > db.persons.find(){ "_id" : 2, "name" : 2 }{ "_id" ...

  6. jQuery.template.js 简单使用

    之前看了一篇文章<我们为什么要尝试前后端分离>,深有同感,并有了下面的评论: 我最近也和前端同事在讨论这个问题,比如有时候前端写好页面给后端了,然后后端把这些页面拆分成很多的 views, ...

  7. SQL批量更新 关系表更新

    很多人在做数据的批量更新时..如果更新的内容是从其他表查出来的..很容易这么写.. UPDATE TABLE1 SET COLUMN1=(SELECT SUM(SOMETHING) FROM TABL ...

  8. SQL 将2张不相关的表拼接成2列,批量更新至另一张表

    update SO_Master set LotteryNo=t2.LotteryNo,UpdateTime=GETDATE() --select sm.LotteryNo,sm.SysNo,t2.L ...

  9. [PDO绑定参数]使用PHP的PDO扩展进行批量更新操作

    最近有一个批量更新数据库表中某几个字段的需求,在做这个需求的时候,使用了PDO做参数绑定,其中遇到了一个坑. 方案选择 笔者已知的做批量更新有以下几种方案: 1.逐条更新 这种是最简单的方案,但无疑也 ...

随机推荐

  1. DevExpress CxGrid 隐藏 Drag a column header to group by that column

  2. 如何修改SQL Server 2000的数据库逻辑与物理名称

    在项目中使用SQL Server 2000创建了一个数据库,发现名称与另一个数据库太相似,于是决定更改名称,包括: 在企业管理器中看到的数据库名,也是实际应用程序中连接用的数据库名称: 在磁盘上看的物 ...

  3. appium----adb shell输入中文/Emoji表情符(ADBKeyBoard)

    前序 “adb shell input textyoyo“ 可以通过adb 输入英文的文本,由于不支持unicode编码,所以无法输入中文,github上有个国外的大神写了个ADBKeyBoard输入 ...

  4. 关于ARM指令那些你必须知道的东西

    1.32位ARM指令每一位都有其作用,具体如下: 低12为第二操作数, 12~15位为目的寄存器, 16~19位为第一操作数, 20~27就是操作码, 28~31就是条件域. 2.多寄存器load和s ...

  5. 一步一步学习IdentityServer4 (2) 开始一个简单的事例

    前面将来一些配置,但是很多都不是必要的,先放一些事例需要的简要配置把 既然是IdentityServer4 所里下面的例子我 直接放到 Linux上 测试环境 CentOS 7 +Nginx1.9.3 ...

  6. Signalr信息推送

    前序 距离上次写文章,差不多已经大半年了.感觉自己越来越懒了,即使有时候空闲下来了,也不想动.前面买了一系列的Python的书,基础的看了大概有四分之一,剩下的基本上还未动,晚上回去也只是吃饭看电影. ...

  7. 【51nod】1564 区间的价值

    题解 这个要注意到一个长度大的区间的最大价值一定比长度小的区间的价值要大 然后我们以每个点为最小值,显然区间越长最大值越大,然后我们更新最大区间长度的取值,这个可以用单调栈求这个最小值能更新到的左右端 ...

  8. OpenContrail 体系

    OpenContrail 体系架构文档 1  概述1.1  使用案例1.2  OpenContrail控制器和vRouter1.3  虚拟网络1.4     Overlay Networking1.5 ...

  9. django中缓存配置

    # ======缓存配置====== CACHES = { ## 虚拟缓存,开发调试版本,此为开始调试用,实际内部不做任何操作 # 'default': { # 'BACKEND': 'django. ...

  10. [BZOJ2669] [cqoi2012]局部极小值

    [BZOJ2669] [cqoi2012]局部极小值 Description 有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次.如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点) ...