日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

mvc一对多模型表单的快速构建

發(fā)布時(shí)間:2023/12/20 c/c++ 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mvc一对多模型表单的快速构建 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

功能需求描述

Q:在實(shí)際的開發(fā)中,經(jīng)常會(huì)遇到一個(gè)模型中包含有多個(gè)條目的表單。如何將數(shù)據(jù)提交到后臺(tái)?
A: 以數(shù)組的形式提交到后臺(tái)就Ok了(真的那么簡單么,如果再嵌套一層呢?)
A2:拆分多個(gè)模型,映射就沒啥問題了。但......有點(diǎn)麻煩啊~~

接下來說說如何將下面的模型提交到后臺(tái)

/// <summary>/// 計(jì)劃模型/// </summary>public class PlanModel{public int Id{ get; set; }/// <summary>/// 計(jì)劃名稱/// </summary>public string PlanName { get; set; }/// <summary>/// 描述/// </summary>public string Remark { get; set; }/// <summary>/// 方案集合/// </summary>public List<CaseModel> Cases { get; set; }}/// <summary>/// 方案模型/// </summary>public class CaseModel{public int Id{ get; set; }/// <summary>/// 標(biāo)題/// </summary>public string Title { get; set; }/// <summary>/// 描述/// </summary>public string Description { get; set; }/// <summary>/// 作者/// </summary>public string Author { get; set; }}

根據(jù)此模型,編輯的頁面會(huì)如下圖所示,一些基本信息加上可增可減的條目

實(shí)現(xiàn)效果

如何實(shí)現(xiàn)這個(gè)功能(asp.net mvc)

  • 新建視圖頁面(略)
  • 條目的顯示增加刪除

    控制器代碼

  • public class HomeController : Controller{[HttpGet]public ActionResult Index(){var model = new PlanModel() {};return View(model);}public ActionResult CaseRow(){return View("_CaseRow", new CaseModel());}[HttpPost]public ActionResult Form(PlanModel model){return Json(model);}}

    編輯頁條目顯示代碼

    <div class="form-group"><label class="col-sm-3 control-label">計(jì)劃方案:</label><div class="col-sm-7 "><table class="table table-bordered table-condensed"><thead><tr class="text-center"><th class="text-center">方案名稱</th><th class="text-center">方案作者</th><th class="text-left">方案描述</th><th class="text-center" width="100"><span>操作</span><span title="添加方案" id="add_case" class="glyphicon glyphicon-plus"></span></th></tr></thead><tbody id="case_list">@if (Model.Cases != null){foreach (var item in Model.Cases){Html.RenderPartial("_CaseRow", item);}}</tbody></table></div></div>

    頁面增加/刪按鈕js代碼 + 驗(yàn)證

    <script src="~/Scripts/jquery.validate.min.js"></script> <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> <script type="text/javascript">$(function () {$("#case_list").delegate(".del_tr", "click", function () {$(this).closest("tr").remove();});$("#add_case").click(function () {//ajax請(qǐng)求返回新增方案視圖代碼$.get('@Url.Action("CaseRow")', function (data) {$("#case_list").append(data);//重置驗(yàn)證模型$("form").removeData("validator").removeData("unobtrusiveValidation");$.validator.unobtrusive.parse($("form"));});});}); </script>

    _CaseRow.cshtml分部視圖代碼

    若要以集合/數(shù)組的形式提交到后臺(tái),須以name[]的格式提交,所以我能想到的就是這樣去寫(這種方案不可取!!)
    但是這樣寫的話且不說太麻煩,驗(yàn)證也不行,一不小心也就寫錯(cuò)了。所以這種方案并不可取

    @{ Layout = null;KeyValuePair<string, string> keyValuePair = new KeyValuePair<string, string>("Cases", Guid.NewGuid().ToString("N"));var prefix = keyValuePair.Key+"["+keyValuePair.Value+"]."; } @model MvcDemo.Models.CaseModel <tr><td><input type="hidden" name="@(keyValuePair.Key+".index")" value="@keyValuePair.Value"/><input type="hidden" class="form-control" name="@(prefix)Id" value="@Model.Id" /><input type="text" class="form-control" name="@(prefix)Title" value="@Model.Title" /></td><td>@Html.TextBox(prefix+nameof(Model.Author),Model.Author, new { @class = "form-control" })</td><td>@Html.TextBox(prefix + nameof(Model.Description), Model.Description, new { @class = "form-control" })</td><td class="text-center"><span class="del_tr glyphicon glyphicon-remove-circle"></span></td> </tr>

    而后發(fā)現(xiàn)大神寫的一個(gè)HtmlPrefixScopeExtensions擴(kuò)展類,可自動(dòng)生成的表單前綴標(biāo)識(shí),使用方便,也能夠使用驗(yàn)證
    只需將表單包裹在@using (Html.BeginCollectionItem("子集合的屬性名稱")){}中即可,文末分享

    @{ Layout = null; } @model MvcDemo.Models.CaseModel @using MvcDemo.Extensions <tr>@using (Html.BeginCollectionItem("Cases")){<td>@Html.HiddenFor(e => e.Id)@Html.TextBoxFor(e => e.Title, new { @class = "form-control" })@Html.ValidationMessageFor(e => e.Title)</td><td>@Html.TextBoxFor(e => e.Author, new { @class = "form-control" })</td><td>@Html.TextBoxFor(e => e.Description, new { @class = "form-control" })</td><td class="text-center"><span class="del_tr glyphicon glyphicon-remove-circle"></span></td>} </tr>

    然后提交表單可以發(fā)現(xiàn)格式如下,并能取到數(shù)據(jù)

    MvcDemo.Extensions命名空間下的HtmlPrefixScopeExtensions擴(kuò)展類

    命名空間自行引用

  • asp.net mvc版本
  • public static class HtmlPrefixScopeExtensions{private const string IdsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";/// <summary>/// /// </summary>/// <param name="html"></param>/// <param name="collectionName"></param>/// <param name="createDummyForm">是否使用虛擬表單,為了解決上下文中不存在表單,無法生成驗(yàn)證信息</param>/// <returns></returns>public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName,bool createDummyForm = false, bool clientValidationEnabled = false){if (clientValidationEnabled == true)html.ViewContext.ClientValidationEnabled = true;if (createDummyForm == true){if (html.ViewContext != null && html.ViewContext.FormContext == null){var dummyFormContext = new FormContext();html.ViewContext.FormContext = dummyFormContext;}}return BeginCollectionItem(html, collectionName, html.ViewContext.Writer);}private static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName, TextWriter writer){var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);var itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().GetHashCode().ToString("x");writer.WriteLine("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />",collectionName, html.Encode(itemIndex));return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));}private static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix){return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);}private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName){var 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 (var previouslyUsedId in previouslyUsedIds.Split(','))queue.Enqueue(previouslyUsedId);}return queue;}internal class HtmlFieldPrefixScope : IDisposable{internal readonly TemplateInfo TemplateInfo;internal readonly string PreviousHtmlFieldPrefix;public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix){TemplateInfo = templateInfo;PreviousHtmlFieldPrefix = TemplateInfo.HtmlFieldPrefix;TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix;}public void Dispose(){TemplateInfo.HtmlFieldPrefix = PreviousHtmlFieldPrefix;}}}
  • asp.net core版本
  • public static class HtmlPrefixScopeExtensions{private const string IdsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";public static IDisposable BeginCollectionItem(this IHtmlHelper html, string collectionName){return BeginCollectionItem(html, collectionName, html.ViewContext.Writer);}private static IDisposable BeginCollectionItem(this IHtmlHelper html, string collectionName, TextWriter writer){if (html.ViewData["ContainerPrefix"] != null)collectionName = string.Concat(html.ViewData["ContainerPrefix"], ".", collectionName);var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);var itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();string htmlFieldPrefix = $"{collectionName}[{itemIndex}]";html.ViewData["ContainerPrefix"] = htmlFieldPrefix;/* * html.Name(); has been removed* because of incorrect naming of collection items* e.g.* let collectionName = "Collection"* the first item's name was Collection[0].Collection[<GUID>]* instead of Collection[<GUID>]*/string indexInputName = $"{collectionName}.index";// 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.writer.WriteLine($@"<input type=""hidden"" name=""{indexInputName}"" autocomplete=""off"" value=""{html.Encode(itemIndex)}"" />");return BeginHtmlFieldPrefixScope(html, htmlFieldPrefix);}private static IDisposable BeginHtmlFieldPrefixScope(this IHtmlHelper html, string htmlFieldPrefix){return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);}private static Queue<string> GetIdsToReuse(HttpContext 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.var key = IdsToReuseKey + collectionName;var queue = (Queue<string>)httpContext.Items[key];if (queue == null){httpContext.Items[key] = queue = new Queue<string>();if (httpContext.Request.Method == "POST" && httpContext.Request.HasFormContentType){StringValues previouslyUsedIds = httpContext.Request.Form[collectionName + ".index"];if (!string.IsNullOrEmpty(previouslyUsedIds))foreach (var previouslyUsedId in previouslyUsedIds)queue.Enqueue(previouslyUsedId);}}return queue;}internal class HtmlFieldPrefixScope : IDisposable{internal readonly TemplateInfo TemplateInfo;internal readonly string PreviousHtmlFieldPrefix;public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix){TemplateInfo = templateInfo;PreviousHtmlFieldPrefix = TemplateInfo.HtmlFieldPrefix;TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix;}public void Dispose(){TemplateInfo.HtmlFieldPrefix = PreviousHtmlFieldPrefix;}}}

    命名空間自行引用~~

    End

    完整源碼:https://coding.net/u/yimocoding/p/WeDemo/git/tree/MvcFormExt/MvcFormExt/MvcDemo

    轉(zhuǎn)載于:https://www.cnblogs.com/morang/p/7593215.html

    總結(jié)

    以上是生活随笔為你收集整理的mvc一对多模型表单的快速构建的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。