表格提交时模型集合丢失
本文关键字:集合 模型 提交 表格 | 更新日期: 2023-09-27 18:06:47
使用模型下面的post请求为两个集合返回null,但它正确返回布尔属性。我的期望是,在get请求期间加载到模型中的集合将持续到post请求。我错过了什么?
编辑:基本上,我正在尝试根据用户选择的selectlist和复选框来更新发票列表。
控制器:
[HttpGet]
[AllowAnonymous]
public async Task<ActionResult> Index(bool displayFalse = true)
{
InvoiceViewModel invoiceView = new InvoiceViewModel();
var companies = new SelectList(await DbContext.Company.ToListAsync(), "CompanyID", "Name").ToList();
var invoices = await DbContext.Invoice.Where(s => s.Paid.Equals(displayFalse)).ToListAsync();
return View(new InvoiceViewModel { Companies = companies,Invoices = invoices, SelectedCompanyID = 0, DisplayPaid = displayFalse});
}
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Index(InvoiceViewModel model)
{
model.Invoices = await DbContext.Invoice.Where(s => s.CompanyID.Equals(model.SelectedCompanyID) && s.Paid.Equals(model.DisplayPaid)).ToListAsync();
return View(model);
}
模型:
public class InvoiceViewModel
{
public int SelectedCompanyID { get; set; }
public bool DisplayPaid { get; set; }
public ICollection<SelectListItem> Companies { get; set; }
public ICollection<Invoice> Invoices{ get; set; }
}
视图:
@model InvoiceIT.Models.InvoiceViewModel
<form asp-controller="Billing" asp-action="Index" method="post" class="form-horizontal" role="form">
<label for="companyFilter">Filter Company</label>
<select asp-for="SelectedCompanyID" asp-items="Model.Companies" name="companyFilter" class="form-control"></select>
<div class="checkbox">
<label>
<input type="checkbox" asp-for="DisplayPaid" />Display Paid
<input type="submit" value="Filter" class="btn btn-default" />
</label>
</div>
<br />
</form>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().InvoiceID)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().CompanyID)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().Description)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().InvoiceDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().DueDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().Paid)
</th>
<th></th>
</tr>
@foreach (var item in Model.Invoices)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.InvoiceID)
</td>
<td>
@Html.DisplayFor(modelItem => item.CompanyID)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td>
@Html.DisplayFor(modelItem => item.InvoiceDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.DueDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Paid)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.InvoiceID }) |
@Html.ActionLink("Details", "Index", "InvoiceItem", new { id = item.InvoiceID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.InvoiceID })
</td>
</tr>
}
</table>
表单只返回控件的名称/值对(input、textarea、select)。由于您生成的两个控件是针对模型的SelectedCompanyID
和DisplayPaid
属性的,因此只有这些属性将在发布时被绑定。
从您的评论来看,您真正想做的是根据所选公司和复选框的值更新发票表。
从性能的角度来看,方法是使用ajax根据控件的值来更新发票表。
创建一个新的控制器方法,返回表行的部分视图
public PartialViewResult Invoices(int CompanyID, bool DisplayPaid)
{
// Get the filtered collection
IEnumerable<Invoice> model = DbContext.Invoice.Where(....
return PartialView("_Invoices", model);
}
注意,如果您希望最初显示未过滤的结果,您可能希望使CompanyID参数为空并调整查询
和局部视图_Invoices.cshtml
@model IEnumerable<yourAssembly.Invoice>
@foreach(var item in Model)
{
<tr>
<td>@Html.DisplayFor(m => item.InvoiceID)</td>
.... other table cells
</tr>
}
在主视图
@model yourAssembly.InvoiceViewModel
@Html.BeginForm()) // form may not be necessary if you don't have validation attributes
{
@Html.DropDownListFor(m => m.SelectedCompanyID, Model.Companies)
@Html.CheckboxFor(m => m.DisplayPaid)
<button id="filter" type="button">Filter results</button>
}
<table>
<thead>
....
</thead>
<tbody id="invoices">
// If you want to initially display some rows
@Html.Action("Invoices", new { CompanyID = someValue, DisplayPaid = someValue })
</tbody>
</table>
<script>
var url = '@Url.Action("Invoices")';
var table = $('#invoices');
$('#filter').click(function() {
var companyID = $('#SelectedCompanyID').val();
var isDisplayPaid = $('#DisplayPaid').is(':checked');
$.get(url, { CompanyID: companyID, DisplayPaid: isDisplayPaid }, function (html) {
table.append(html);
});
});
</script>
另一种选择是按原样发布表单,但不是返回视图,而是使用
return RedirectToAction("Invoice", new { companyID = model.SelectedCompanyID, DisplayPaid = model.DisplayPaid });
并修改GET方法以接受附加参数。
边注:您使用TagHelpers
来生成
select asp-for="SelectedCompanyID" asp-items="Model.Companies" name="companyFilter" class="form-control"></select>
我对它们不太熟悉,但如果name="companyFilter"
工作(并覆盖默认名称name="SelectedCompanyID"
),那么你生成的name
属性与你的模型属性不匹配,因此SelectedCompanyID
将是0
(默认为int
)在POST方法。
将ToList()
附加到填充companies
的语句中是将SelectList
转换为List<T>
,窗体将不识别为SelectList
。此外,通过使用动态var
关键字,您可以屏蔽此问题。试试这个:
SelectList companies = new SelectList(await DbContext.Company.ToListAsync(), "CompanyID", "Name");
一般来说,尽量避免使用var
,除非该类型是真正动态的(在运行时之前未知)。
您将模型数据置于表单之外,因此它不会提交!
<form asp-controller="Billing" asp-action="Index" method="post" class="form-horizontal" role="form">
<label for="companyFilter">Filter Company</label>
<select asp-for="SelectedCompanyID" asp-items="Model.Companies" name="companyFilter" class="form-control"></select>
<div class="checkbox">
<label>
<input type="checkbox" asp-for="DisplayPaid" />Display Paid
<input type="submit" value="Filter" class="btn btn-default" />
</label>
</div>
<br />
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().InvoiceID)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().CompanyID)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().Description)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().InvoiceDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().DueDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().Paid)
</th>
<th></th>
</tr>
@foreach (var item in Model.Invoices)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.InvoiceID)
</td>
<td>
@Html.DisplayFor(modelItem => item.CompanyID)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td>
@Html.DisplayFor(modelItem => item.InvoiceDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.DueDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Paid)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.InvoiceID }) |
@Html.ActionLink("Details", "Index", "InvoiceItem", new { id = item.InvoiceID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.InvoiceID })
</td>
</tr>
}
</table>
</form>
使用for循环来创建与公司相关的列表,可以映射回并保存公司值
for(c = 0 ; c < Model.Companies.Count(); c++)
{
<input type='hidden' name='@Html.NameFor(Model.Companies[c].Propery1)' id='@Html.IdFor(Model.Comapnies[c].Propery1)' value='somevalue'>someText />
<input type='hidden' name='@Html.NameFor(Model.Companies[c].Propery2)' id='@Html.IdFor(Model.Comapnies[c].Propery2)' value='somevalue'>someText />
}
这确保列表被映射回默认的模型绑定器期望列表是ListProperty[index]格式