• MVC批量更新,使用jQuery Template


    在"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>

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

        <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);
            }
        }
    }    
     


    □ 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>

     

    □ 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");
            }

     

    □ 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>
    }
     


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

  • 相关阅读:
    DML、DDL、DCL的区别
    exe文件图标不见了,教你win10桌面EXE文件图标不见了如何解决
    js获取近十二个月
    关于tomcat中的三个端口的作用及其相关细节
    js判断对象是否为空对象的几种方法
    解决myeclipse validation验证javascript导致速度变慢的现象
    jQuery基础教程之is()方法和has() 方法
    2015年6月发布了ECMAScript6版本
    http系列--从输入 URL 到页面加载完成的过程
    一篇文看懂Hadoop
  • 原文地址:https://www.cnblogs.com/darrenji/p/3717770.html
Copyright © 2020-2023  润新知