[英]Submitting one of multiple forms from editor template to a controller action
我有一個顯示帶有動態任務列表的清單的應用程序。 目前,所有任務都有2個單選按鈕:一個用於“完成”,一個用於“未完成”。 稍后,我將添加新的任務類型(文本框等)。
主視圖調用一個創建每個任務的編輯器模板。 清單模型將任務保留在List<Task>
類型的屬性“ Tasks”中。 這很好顯示,但是在表單提交上有麻煩。
我希望每個任務獨立保存,因此我在編輯器模板中的控件周圍放置了<form>
元素。
調節器
public class CheckController : Controller
{
[HttpGet]
public ActionResult Index()
{
var checklist = new Checklist();
GetData(checklist);
return View(checklist);
}
[HttpPost]
public ActionResult Index(Task model)
{
var task = (Task)model;
return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
}
}
楷模
public class Checklist
{
public List<Task> Tasks { get; set; }
public Checklist()
{
Tasks = new List<Task>();
}
}
public class Task
{
public int TaskId { get; set; }
public string TaskName { get; set; }
public bool IsDone { get; set; }
}
查看
@model Checkpoint.Models.Checklist
<table>
@Html.EditorFor(x => x.Tasks);
</table>
@model Checkpoint.Models.Task
<tr>
<td>@Model.TaskName</td>
<td data-ftid="@Model.TaskId">
@{
using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
@Html.HiddenFor(x => x.TaskId)
@Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
@Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
}
</td>
</tr>
呈現的HTML
<tr>
<td>First thing</td>
<td>
<form action="/Checklist" method="post">
<input id="Tasks_0__TaskId" name="Tasks[0].TaskId" type="hidden" value="1" />
<input checked="checked"id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="False" />
<span>Incomplete</span>
<input id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="True"
<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
</form>
</td>
</tr>
<tr>
<td>Second thing</td>
<td>
<form action="/Checklist" method="post">
<input id="Tasks_1__TaskId" name="Tasks[1].TaskId" type="hidden" value="2" />
<input checked="checked" id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="False" />
<span>Incomplete</span>
<input id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="True" />
<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
</form>
</td>
</tr>
這確實提交了請求,但是數據如下所示:
Tasks[1].TaskId: 1
Tasks[1].IsDone: True
當它到達控制器動作(接受Task類型)時,屬性值為null。
如何在控制器操作中正確獲取任務數據? 還是我要以完全錯誤的方式進行此操作?
獎勵:添加新任務類型的最佳方法是什么?
由於您不打算一次提交所有集合,因此您將需要丟失模型名稱的索引。
Tasks[0].TaskId
調整您的視圖。 變量名稱“ task”需要與action參數匹配,因為HtmlHelpers將基於此字符串生成名稱屬性。
@model Checkpoint.Models.Checklist
<table>
@foreach(Task task in Model.Tasks)
{
@Html.EditorFor(m => task)
}
</table>
呈現的html看起來像
<input id="task_TaskId" name="task.TaskId" type="hidden" value="1">
...
該操作需要一個“任務”參數來匹配以綁定其值
[HttpPost]
public ActionResult Index(Task task)
{
return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
}
如果我們使用局部視圖而不是編輯器模板,則可以稍微放寬對“任務”的名稱依賴。
@model Checkpoint.Models.Checklist
<table>
@foreach(Task t in Model.Tasks)
{
@Html.PartialView("_TaskForm", t)
}
</table>
並且您的編輯器模板內容將完全相同。
_TaskForm
@model Checkpoint.Models.Task
<tr>
<td>@Model.TaskName</td>
<td data-ftid="@Model.TaskId">
@{
using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
@Html.HiddenFor(x => x.TaskId)
@Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
@Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
}
</td>
</tr>
和渲染的html
<input id="TaskId" name="TaskId" type="hidden" value="1">
...
上面所有的問題是html id
屬性將不是唯一的。 因此,如果這很關鍵,則需要手動迭代該集合以手動構建每個表單,以便您可以精確地指定id值。 也就是說,您將丟失小型的模塊化編輯器模板。
讓框架自動生成“唯一” ids ...我們重寫name屬性(注意“ Name”的大小寫),我們有:
@model Checkpoint.Models.Checklist
<table>
@for(int i = 0; i < Model.Tasks.Count; i++)
{
<tr>
<td>@Model.Tasks[i].TaskName</td>
<td data-ftid="@Model.Tasks[i].TaskId">
@using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
@Html.HiddenFor(x => Model.Tasks[i].TaskId, new { Name="TaskId" })
@Html.RadioButtonFor(x => Model.Tasks[i].IsDone, false, new { Name="IsDone" })<span>Incomplete</span>
@Html.RadioButtonFor(x => Model.Tasks[i].IsDone, true, new { Name="IsDone" })<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
</td>
</tr>
}
</table>
通過拖放幫助器並手動創建控件,我可以使用“編輯器模板”來實現此目的。
@model Checkpoint.Models.Task
<tr>
<td>@Model.TaskName</td>
<td data-ftid="@Model.TaskId">
@using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
<input name="TaskId" type="hidden" value="@Model.TaskId" />
<input name="IsDone" type="radio" value="True" @Html.Raw(Model.IsDone ? "checked=checked" : null) />
<span>Complete</span>
<input name="IsDone" type="radio" value="False" @Html.Raw(!Model.IsDone ? "checked=checked" : null) />
<span>Incomplete</span>
<button role="button" type="submit" name="taskAction" value="@Model.TaskId">Submit</button>
}
</td>
</tr>
我對此並不是很滿意,而是選擇了@Jasen的局部視圖解決方案。 通過覆蓋助手中的'id'屬性,我可以獲得唯一的元素ID。 我使用TaskId,因為它是唯一的,但否則可以從主視圖傳遞循環索引。
@model Checkpoint.Models.Task
<tr>
<td>@Model.TaskName</td>
<td data-ftid="@Model.TaskId">
@using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
@Html.HiddenFor(x => x.TaskId, new { id = "Task_" + Model.TaskId + "_hidIsDone" })
@Html.RadioButtonFor(x => x.IsDone, false, new { id = "Task_"+ Model.TaskId + "_radIsDoneF" })<span>Incomplete</span>
@Html.RadioButtonFor(x => x.IsDone, true, new { id = "Task_" + Model.TaskId + "_radIsDoneT" })<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
</td>
</tr>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.