第一次發文章,排版上簡單粗糙了些。如果內容中有什么錯誤之處,歡迎指正。相互學習,共同提高。
本人受http://shiyousan.com/post/635383025861004585 此文啟發。尊重原創。
大多數時候我們提交的web表單內容都是之前就決定好的。
比如在 csdn 個人主頁中編輯簡介的時候看到的表單。
這樣的表單是固定的,因為它足夠簡單,而且被擴展的可能性也不大。
但是你總會遇到一些讓你頭疼的需求。
不多廢話,我們直接進主題。
假如我們有一個實體類A,A中有一個屬性 List<B> Member。
代碼如下:

1 public class Dept 2 3 { 4 5 public int Id { get; set; } 6 7 public string Name { get; set; } 8 9 public string Description { get; set; } 10 11 public List<Employee> Members {get; set; } 12 13 } 14 15 16 17 public class Employee 18 19 { 20 21 public int Id { get; set; } 22 23 public string Name { get; set; } 24 25 public int Age { get; set; } 26 27 }
我們希望在編輯Dept的時候也可以同時編輯Members中的各個子集Employee。
我們先在Dept控制器中創建Index方法,並在其中初始化一點測試數據。具體如下:

1 public class DeptController : Controller 2 3 { 4 5 public ViewResult Index() 6 7 { 8 9 var dept = new Dept() { 10 11 Id = 1, 12 13 Name = "First Dept", 14 15 Description = string.Empty, 16 17 Members = newList<Employee>() 18 19 }; 20 21 dept.Members.Add(new Employee() { 22 23 Id = 1, 24 25 Name = "犀利的綿羊", 26 27 Age = 24 28 29 }); 30 31 return View(dept); 32 33 } 34 35 36 37 [HttpPost] 38 39 public ActionResult Index(Dept dept) 40 41 { 42 43 var membersCount = dept.Members.Count; 44 45 var t = dept; 46 47 return Json("done",JsonRequestBehavior.DenyGet); 48 49 } 50 51 }
接下來我們創建Index視圖,我們可以看到Index方法中的視圖模型是Dept類,在Index視圖起始位置寫上@model Dept(注意:如果運行出錯,可以在Dept之前加上完整的命名空間,也可以在Views目錄下的web.config文件中添加命名空間,類似<addnamespace="YourNamespace" />)

1 @modelDept 2 3 4 5 @using(Html.BeginForm()) 6 7 { 8 9 <div> 10 11 <table > 12 13 <caption>部門信息</caption> 14 15 <tr> 16 17 <td>名稱</td> 18 19 <td>@Html.TextBoxFor(x=>x.Name)</td> 20 21 </tr> 22 23 <tr> 24 25 <td>描述</td> 26 27 <td>@Html.TextBoxFor(x=>x.Description)</td> 28 29 </tr> 30 31 <tr> 32 33 <td>成員</td> 34 35 <td> 36 37 <ul> 38 39 @for(var i = 0; i <Model.Members.Count; i++) 40 41 { 42 43 <li> 44 45 姓名:@Html.TextBoxFor(x=>x.Members[i].Name) 46 47 年齡:@Html.EditorFor(x=>x.Members[i].Age) 48 49 <inputtype="button" value="刪除" class="deleteMember" /> 50 51 </li> 52 53 } 54 55 </ul> 56 57 </td> 58 59 </tr> 60 61 </table> 62 63 </div> 64 65 <input type="submit"value="保存"/> 66 67 }
我們可以看到,在處理Members時,我們用到了for循環和Html輔助方法。
生成的姓名和年齡對應的文本框的id和name屬性都會包含for循環中 i 的值,也就是下標。截圖如下:
下圖是生成的頁面
接下來就是前端的工作了,js代碼如下:

1 $(function() { 2 3 init(); 4 5 }) 6 7 8 9 function init() { 10 11 $(".addMember").remove(); 12 13 $(".deleteMember").last().after("<input type='button'value='添加' class='addMember'/>"); 14 15 initAddBtn(); 16 17 initDeleteBtn(); 18 19 } 20 21 22 23 function initDeleteBtn() { 24 25 $(".deleteMember").unbind(); 26 27 $(".deleteMember").click(function() { 28 29 var memberCount =$(".deleteMember").length; 30 31 if (memberCount <= 1) { 32 33 alert("溫馨提示:至少得有一個員工哦"); 34 35 return false; 36 37 } 38 39 40 41 // 修改當前員工下方的所有員工的可編輯框的屬性(id, name) 42 43 $(this).parents("li").nextAll().each(function () { 44 45 // 獲取輸入框 46 47 var txts =$(this).children("input[type='text'], input[type='number']"); 48 49 // 獲取當前員工name屬性中的數字,也就是 Members 屬性的下標 50 51 var index =Number(txts.eq(0).attr("name").match(/\d+/)[0]); 52 53 txts.each(function () { 54 55 // 修改屬性中的數字的值, 當前員工下標 -1 56 57 $(this).attr("id",$(this).attr("id").replace(/\d+/, index - 1)); 58 59 $(this).attr("name",$(this).attr("name").replace(/\d+/, index - 1)); 60 61 }) 62 63 }) 64 65 // 刪除當前 li 標簽 66 67 $(this).parents("li").remove(); 68 69 init(); 70 71 }); 72 73 } 74 75 function initAddBtn() { 76 77 $(".addMember").unbind(); 78 79 $(".addMember").click(function (){ 80 81 // 復制當前 li 標簽,並添加到當前 li 標簽后面,形成添加效果 82 83 var parent =$(this).parents("li").clone(); 84 85 $(this).parents("li").after(parent); 86 87 88 89 // 清空復制項的各個編輯框 90 91 var txts =parent.children("input[type='text'], input[type='number']"); 92 93 txts.val(""); 94 95 96 97 // 獲取復制項中“姓名”框的name屬性中的數字,也就是 Members 屬性的下標 98 99 var index =Number($(this).siblings().eq(0).attr("name").match(/\d+/)[0]); 100 101 txts.each(function () { 102 103 // 新增的員工的 Member 下標 +1 104 105 $(this).attr("id",$(this).attr("id").replace(/\d+/, index + 1)); 106 107 $(this).attr("name",$(this).attr("name").replace(/\d+/, index + 1)); 108 109 }) 110 111 // 刪除當前 “添加” 按鈕 112 113 $(this).remove(); 114 115 init(); 116 117 }) 118 119 }
需要注意的是“添加”和“刪除”按鈕的點擊事件的處理邏輯(就好像操作List一樣,刪除List中的一個元素,則后方的所有元素的下標要-1, 添加的元素在尾部,其下標值是List.Count - 1)。
當我們提交這個表單的時候,Dept的其他字段不用特別在意,但是Members字段的所有下標不能間斷,且需從0開始,依次遞增。
下面附上調試截圖為依據:(生成的html不太好看,下圖中的html是經過調整的)
點擊“保存”,然后我們可以看到如下的調試信息,此時的dept.Members有三個元素。而且各個元素的屬性與填寫的表單內容一致。
現在我們修改一下html中的一部分,再看看操作操作結果:
我們可以看到第三個元素的下標改成了3,形成了0,1,3 的不連續的情況。點擊“保存”,我們看調試信息:
我們可以看到只接收到前兩個元素。不連續的第三個元素已經丟失。
我們再看看第一個元素下標不為零的情況:
可以看到Members沒有接收到任何元素。
現在我們證實了上面的觀點。
下面我們來引申一下,如果我們試圖的模型是List<Employee>而不是Dept,我們是不是也可以用這種方法做到多個元素同時編輯?我想應該是沒問題的。不用那些JS插件,我們一樣可以實現行內編輯哦。