我需要在一些页面上添加一些功能,所以我将其作为局部视图实现。
在这个局部视图中,我有一个下拉列表,一个添加按钮和一个“项目”,每个项目都包含一个删除按钮。功能很明显。单击任何删除按钮将删除关联的项目,从下拉列表中选择一个项目,然后单击添加添加该项目。
复杂性是这需要完全在javascript中发生 - 对项目列表的更改需要完全在客户端发生,并且在提交表单之前服务器上没有任何事情发生。 (也就是说,我们不希望在每次更改时通过ajax更新服务器,我们希望收集更改并在表单提交时提交它们。)
第二个复杂性是这个表单需要相当多的插入,对父视图的要求尽可能少。
所以我为partial创建了一个viewmodel:
public class ItemsModel
{
// The list to be displayed in the dropdown
public List<KeyValuePair<string, string>> itemsList { get; set; }
// The list of selected items
public List<string> items { get; set; }
public string itemsJson
{
get { return JsonConvert.SerializeObject(this.items); }
set { this.items = JsonConvert.DeserializeObject<List<string>>(value);
}
public ItemsModel()
{
this.itemsList = new List<KeyValuePair<string, string>>();
this.items = new List<string>();
}
}
页面的viewmodel包含以下实例:
public class MyViewModel
{
// Assorted stuff
public ItemsModel itemsModel;
}
当Controller构建模型时,在HttpGet期间,它使用两个列表填充ItemsModel对象。页面视图包含partial,传递itemsModel:
@{Html.RenderPartial("_itemsList", Model.itemsModel);
在部分内容中,我构建了下拉列表:
@Html.DropDownList("itemsList", new SelectList(Model.itemsList, "Key", "Value")
我用javascript填充:
var items = $.parseJSON('@Html.Raw(Model.itemsJson)');
var itemsUl = $('#itemsUl');
itemsUl.empty();
var iTemplate = $('#itemTemplate').html();
for (var i=0; i<items.length; i++)
{
var template = iTemplate.nformat("{item}": items[i]);
itemsUl.append($(template));
}
就我而言,这就是我的意思。我的意图是添加javascript来处理插入和删除,但此时没有意义。因为当我使用未修改的列表提交页面时,MyViewModel.itemsModel为null。在网上浏览,我看过很多关于MVC如何将Request项绑定到复杂列表的帖子,但是没有一个与我的问题相关,因为没有任何东西可以让MVC受到约束。
我在Fiddler看过,正在发送的请求包括“......&amp; itemsList =&amp; ...” - 它根本没有发送任何数据。
所以我想知道我是否正在追逐错误的道路。在表单提交中包含复杂数据的常规方法是什么?我已经读过FormData(),但这似乎只适用于Ajax风格的发送,它不会影响正常的表单提交。
有什么想法吗?
答案 0 :(得分:0)
像往常一样,在这些问题中,我只是没有考虑事情。
如果我希望在表单提交期间将值包含在请求中,我需要输入表单元素。
首先,我删除了并行json属性 - 内联序列化/反序列化很容易,它使得更明显的是发生了什么。所以我的模型变成了:
public class ItemsModel
{
// The list to be displayed in the <select>
public List<string> itemsList { get; set; }
// The list of selected items
public List<string> items { get; set; }
public ItemsModel()
{
this.itemsList = new List<string>();
this.items = new List<string>();
}
}
该列表仅发送到浏览器,它不需要返回,因此可以直接注入javascript变量:
var itemsSelect = $('#itemsSelect');
itemsSelect.find('option').remove();
var itemsList =
$.parseJSON('@Html.Raw(JsonConvert.SerializeObject(Model.itemsList))');
for (i = 0; i < itemsList.length; i++)
{
var item = itemsList[i];
itemsSelect
.append($("<option>", { value: item })
.text(item ? item : "Select Item"));
}
然而,这些物品需要回来。这意味着json需要作为隐藏元素注入页面:
@Html.Hidden("itemsJson", JsonConvert.SerializeObject(Model.items))
然后在javascript中,我们将数据提取到数组中:
var items = JSON.parse($('#itemsJson').val());
然后我从这些元素构建&lt; li&gt;并将它们添加到我的&lt; ul&gt;。然后,用户从&lt; select&gt;中选择一个项目。然后点击“添加”按钮,或点击其中一个&lt; li&gt;中的“删除”按钮,然后删除&lt; option&gt;从下拉列表中添加&lt; li&gt;到&lt; ul&gt;,或者删除&lt; li&gt;来自&lt; ul&gt;并添加&lt;选项&gt;到&lt; select&gt;。在任何一种情况下,我都需要重新序列化数组并更新隐藏的元素:
$('#itemsJson').val(JSON.stringify(items));
然后,当我提交表单时,浏览器将在请求中包含一个名为“itemsJson”的JSON字符串。唯一剩下的问题是如何将其纳入HttpPost行动。有三种可能性:
我选择了选项3:
[Authorize]
[HttpPost]
public ActionResult Perishable(MyViewModel model, string itemsJson)
{
if (ModelState.IsValid)
{
model.itemsModel= new ItemsModel
{
items= JsonConvert.DeserializeObject<List<string>>(itemsJson)
};
...
}
}