如何将项目列表从视图传递到控制器(ASP.NET MVC 4)
Posted
技术标签:
【中文标题】如何将项目列表从视图传递到控制器(ASP.NET MVC 4)【英文标题】:How to Pass a List of Items from View to Controller (ASP.NET MVC 4) 【发布时间】:2016-09-10 06:42:49 【问题描述】:我正在尝试将多个 List
我希望在视图中有一个“费用”列表,每个“费用”或项目旁边都有一个来自模型中 Submitted 布尔属性的复选框。当我检查项目时,我希望在数据库中更新检查项目的属性列表 Submitted 和 DateSubmitted。
视图中的@Html.DisplayFor(modelItem => item.Submitted) 会生成复选框。
我做错了什么?
这是我的观点:
@model IEnumerable<Expenses.Models.Expense>
@
ViewBag.Title = "Submit Expenses";
Layout = "~/Views/Shared/_Layout.cshtml";
DateTime today = DateTime.Today;
string formattedDate = today.ToString("MM/dd/yyyy");
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<h2>Submit Expenses</h2>
@using (Html.BeginForm())
@Html.AntiForgeryToken()
<div class="form-inline">
<div class="form-group">
<h4>Start Date:</h4>
<div class="col-md-10">
@Html.TextBox("expenseDate", formattedDate, htmlAttributes: new
@class = "form-control"
)
</div>
</div>
<div class="form-group">
<h4>End Date:</h4>
<div class="col-md-10">
@Html.TextBox("expenseDate2", formattedDate, htmlAttributes: new
@class = "form-control"
)
</div>
</div>
<div class="form-group">
@if (User.IsInRole("admin"))
<h4>Username:</h4>
<div class="editor-field">
@Html.DropDownList("UserId", String.Empty)
</div>
</div>
<br />
<br />
<div class="form-group">
<div class="col-md-2">
<input type="submit" value="Retrieve Expenses" class="btn btn-default" />
</div>
</div>
</div>
<br />
<br />
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table style="margin-bottom: 20px;">
<tr>
<th>
@Html.DisplayNameFor(model => model.Company)
</th>
<th>
@Html.DisplayNameFor(model => model.Category)
</th>
<th>
@Html.DisplayNameFor(model => model.Province)
</th>
<th>
@Html.DisplayNameFor(model => model.ReceiptName)
</th>
<th>
@Html.DisplayNameFor(model => model.Comment)
</th>
<th>
@Html.DisplayNameFor(model => model.GrossAmount)
</th>
<th>
@Html.DisplayNameFor(model => model.TaxAmount)
</th>
<th>
@Html.DisplayNameFor(model => model.NetAmount)
</th>
<th>
@Html.DisplayNameFor(model => model.Mileage)
</th>
<th>
@Html.DisplayNameFor(model => model.TravelStatus)
</th>
<th>
@Html.DisplayNameFor(model => model.LunchLearnStatus)
</th>
<th>
@Html.DisplayNameFor(model => model.WithClientStatus)
</th>
<th>
@Html.DisplayNameFor(model => model.DateEntered)
</th>
<th>
@Html.DisplayNameFor(model => model.DateSubmitted)
</th>
<th>
@Html.DisplayNameFor(model => model.ExpenseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.ImageName)
</th>
@if (User.IsInRole("admin"))
<th>
@Html.DisplayNameFor(model => model.UserProfile.UserName)
</th>
<th></th>
</tr>
<tr>
<td>
<b>Select All:</b>
<br />
<input type="checkbox" name="expense" value="Expense" id="selectAllCheckboxes" class="expenseCheck">
</td>
</tr>
@foreach (var item in Model)
<tr>
<td class="submitCheck">
@Html.EditorFor(modelItem => item.Submitted)
</td>
<td>
@Html.DisplayFor(modelItem => item.Company)
</td>
<td>
@Html.DisplayFor(modelItem => item.Category)
</td>
<td>
@Html.DisplayFor(modelItem => item.Province)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReceiptName)
</td>
<td>
@Html.DisplayFor(modelItem => item.Comment)
</td>
<td>
@Html.DisplayFor(modelItem => item.GrossAmount)
</td>
<td>
@Html.DisplayFor(modelItem => item.TaxAmount)
</td>
<td>
@Html.DisplayFor(modelItem => item.NetAmount)
</td>
<td>
@Html.DisplayFor(modelItem => item.Mileage)
</td>
<td>
@Html.DisplayFor(modelItem => item.TravelStatus)
</td>
<td>
@Html.DisplayFor(modelItem => item.LunchLearnStatus)
</td>
<td>
@Html.DisplayFor(modelItem => item.WithClientStatus)
</td>
<td>
@Html.DisplayFor(modelItem => item.DateEntered)
</td>
<td>
@Html.DisplayFor(modelItem => item.DateSubmitted)
</td>
<td>
@Html.DisplayFor(modelItem => item.ExpenseDate)
</td>
<td>
@if (item.ImageName != null)
<a href="~/Images/@Html.DisplayFor(modelItem => item.UserProfile.FullName)/@Html.DisplayFor(modelItem => item.ImageName)" class="imageClick" target="_blank"><img src="~/Images/@Html.DisplayFor(modelItem => item.UserProfile.FullName)/@Html.DisplayFor(modelItem => item.ImageName)" style="width:80%" /></a>
</td>
@if (User.IsInRole("admin"))
<td>
@Html.DisplayFor(modelItem => item.UserProfile.UserName)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new id = item.ExpenseId ) |
@Html.ActionLink("Details", "Details", new id = item.ExpenseId ) |
@if (User.IsInRole("admin"))
@Html.ActionLink("Delete", "Delete", new id = item.ExpenseId )
</td>
</tr>
</table>
@Html.ActionLink("Submit Expenses", "SubmitExpenses", "Expenses", null, new @class = "submitLink", @style = "background-color: #d3dce0; border: 1px solid #787878; cursor: pointer; font-size: 1.5em; font-weight: 600; margin-right: 8px; padding: 7px; width: auto; text-decoration: none; font-weight:bold;")
<div class="ExportSection" style="margin-top:30px;">
@*<a href="javascript:void(0)">Export To CSV</a>*@
@Html.ActionLink("Export To CSV", "ExportExpensesListToCSV")
</div>
@section scripts
<script type="text/javascript">
$("#selectAllCheckboxes").click(function ()
$('.submitCheck input:checkbox').not(this).prop('checked', this.checked);
);
$(function ()
$("#expenseDate").datepicker();
);
$(function ()
$("#expenseDate2").datepicker();
);
</script>
这是我的控制器方法:
public ActionResult SubmitExpenses(List<Expense> expenses, DateTime? expenseDate = null, DateTime? expenseDate2 = null, int? userId = 0)
expenseDate = (DateTime)Session["FirstDate"];
expenseDate2 = (DateTime)Session["SecondDate"];
if (expenseDate == null || expenseDate2 == null)
expenseDate = DateTime.Now.AddMonths(-1);
expenseDate2 = DateTime.Today;
string currentUserId = User.Identity.Name;
var query = from e in db.Expenses
join user in db.UserProfiles on e.UserId equals user.UserId
where e.ExpenseDate >= expenseDate && e.ExpenseDate <= expenseDate2 && e.DateSubmitted == null
orderby e.ExpenseDate descending
select new e, user ;
if (User.IsInRole("admin") && userId != 0)
query = query.Where(x => x.user.UserId == userId);
else if (!User.IsInRole("admin"))
query = query.Where(x => x.user.UserName == currentUserId);
var expensesFromView = expenses;
var joined = from dbExpense in query.Select(x => x.e).AsEnumerable()
join localExpense in expenses on dbExpense.ExpenseId equals localExpense.ExpenseId
where localExpense.Submitted
select dbExpense;
foreach (Expense exp in joined)
exp.DateSubmitted = DateTime.Today;
try
db.SaveChanges();
return RedirectToAction("Index");
catch (Exception e)
Console.WriteLine(e);
return RedirectToAction("Submit");
这是我的模型:
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ExpenseId get; set;
[Required]
public string Company get; set;
[Required]
public string Category get; set;
[Required]
[Display(Name = "Receipt Name")]
public string ReceiptName get; set;
public string Comment get; set;
[Required]
public string Province get; set;
[Required]
[Display(Name = "Gross Amount")]
public decimal GrossAmount get; set;
[Required]
[Display(Name = "GST/HST Amount")]
public decimal TaxAmount get; set;
[Required]
[Display(Name = "Net Amount")]
public decimal NetAmount get; set;
[Display(Name = "Mileage (in Kilometers)")]
public int Mileage get; set;
[Display(Name = "Travelling?")]
public bool TravelStatus get; set;
[Display(Name = "Lunch & Learn?")]
public bool LunchLearnStatus get; set;
[Display(Name = "With Clients?")]
public bool WithClientStatus get; set;
[DisplayFormat(DataFormatString = "0:MM/dd/yyyy")]
[Required]
[Display(Name = "Date Entered")]
public DateTime? DateEntered get; set;
[DisplayFormat(DataFormatString = "0:MM/dd/yyyy")]
[Display(Name = "Date Submitted")]
public DateTime? DateSubmitted get; set;
[DisplayFormat(DataFormatString = "0:MM/dd/yyyy")]
[Required]
[Display(Name = "Expense Date")]
public DateTime? ExpenseDate get; set;
[Display(Name = "Image")]
public string ImageName get; set;
[Display(Name = "Submitted?")]
public bool Submitted get; set;
[Required]
[Display(Name = "Name")]
public int UserId get; set;
[ForeignKey("UserId")]
public virtual UserProfile UserProfile get; set;
我的变量 expensesFromView
显示为 null,因此,我的 joined
查询出现错误:
值不能为空。参数名称:inner
【问题讨论】:
【参考方案1】:我真的找不到将项目列表直接从 View 传递到 Controller 的方法,所以我决定使用 AJAX。
我将控制器的参数从 List 类型更改为 int[ ] 以获取项目 ID 数组:
public ActionResult SubmitExpenses(int[] expenseIDs, DateTime? expenseDate = null, DateTime? expenseDate2 = null, int? userId = 0)
expenseDate = (DateTime)Session["FirstDate"];
expenseDate2 = (DateTime)Session["SecondDate"];
if (expenseDate == null || expenseDate2 == null)
expenseDate = DateTime.Now.AddMonths(-1);
expenseDate2 = DateTime.Today;
string currentUserId = User.Identity.Name;
var query = from e in db.Expenses
join user in db.UserProfiles on e.UserId equals user.UserId
where e.ExpenseDate >= expenseDate && e.ExpenseDate <= expenseDate2 && e.DateSubmitted == null
orderby e.ExpenseDate descending
select new e, user ;
if (User.IsInRole("admin") && userId != 0)
query = query.Where(x => x.user.UserId == userId);
else if (!User.IsInRole("admin"))
query = query.Where(x => x.user.UserName == currentUserId);
//var localExpenseIDs = expenseIDs;
var joined = from dbExpense in query.Select(x => x.e).AsEnumerable()
join localExpense in expenseIDs on dbExpense.ExpenseId equals localExpense
where localExpense == dbExpense.ExpenseId
select dbExpense;
foreach (Expense exp in joined)
exp.DateSubmitted = DateTime.Today;
exp.IsSubmitted = true;
try
db.SaveChanges();
return RedirectToAction("Index");
catch (Exception e)
Console.WriteLine(e);
return RedirectToAction("Submit");
在我看来,我将每个项目的 ID 分配给它自己的 HTML 复选框的 ID:
@foreach (var item in Model)
<tr>
<td class="checkbox-td">
@Html.CheckBox("isSubmitted", new
@id = @Html.DisplayFor(modelItem => item.ExpenseId),
@class = "submitBox"
)
</td>
</tr>
<div>
@Html.ActionLink("Submit Expenses", "", "", null, new @id = "submitExpensesLink" )
</div>
我写了一些 jQuery,以便每个选中的复选框都会将输入元素的 id 添加到数组中,并且整数数组将 POST 到 SubmitExpenses强>行动:
var checkedArray = [];
$(':checkbox[name=isSubmitted]').on('change', function ()
checkedArray = $(':checkbox[name=isSubmitted]:checked').map(function ()
return this.id;
)
.get();
//alert(checkedArray);
);
$('#submitExpensesLink').click(function ()
$.ajax(
type: "POST",
traditional: true,
url: "@Url.Action("SubmitExpenses", "Expenses")",
data: expenseIDs: checkedArray ,
success: function ()
alert("Success!");
,
error: function (XMLHttpRequest, textStatus, errorThrown)
if (debug)
alert(XMLHttpRequest.responseText);
alert(textStatus);
alert(errorThrown);
);
)
【讨论】:
【参考方案2】:有两种方法可以做到这一点 -
1 .
您可能需要这个非常好且可扩展的扩展 - MvcCheckBoxList -- 好像这个网站已经被关闭了 :) 参考选项 2
2.
@for (int i = 0; i < Model.Count; i++)
<tr>
<td class="submitCheck">
<input type="checkbox" value="@Model[i].Id" name="Expense[@i].Id">
<input type="hidden" value="0" name="Expense[@i].Id">
</td>
<td>
@Html.DisplayFor(modelItem => item.Company)
</td>
</tr>
顺便说一句:如果您使用第二种方式:在您的控制器中,过滤费用对象 ID 的零值;因为如果它没有被选中,零会被发送到控制器(作为元素的 ID)宽限期到您可以在上面的代码中看到的“隐藏”字段。
【讨论】:
谢谢哥们。你给我的链接似乎是我需要的。我会试试这个,如果它有效,请告诉你!【参考方案3】:1) 将FormMethod.Post
添加到@using (Html.BeginForm())
@using (Html.BeginForm("nameAction", "nameController", FormMethod.Post))
//Your code
2) 您应该为这样的输入添加名称:
<input type="text" name="someName"/>
【讨论】:
感谢您的回答。我已经尝试过了,但数据仍然没有正确传递。以上是关于如何将项目列表从视图传递到控制器(ASP.NET MVC 4)的主要内容,如果未能解决你的问题,请参考以下文章
通过组合动作链接和 ASP.Net MVC 5 中的输入将用户键入的输入从视图传递到动作控制器?