Asp.net mvc 4 在ASP.NET MVC 4和KnockoutJS中使用主详细信息表单时视图不更新
我正在尝试使用ASP.NETMVC4和KnockoutJS为数据记录创建一个单页编辑器。它非常简单,有一个显示记录的表和一个编辑单个记录的表单 单击“编辑”编辑记录时,表单将更新,数据将毫无问题地保留到数据库中。这之后有两个问题:Asp.net mvc 4 在ASP.NET MVC 4和KnockoutJS中使用主详细信息表单时视图不更新,asp.net-mvc-4,knockout.js,Asp.net Mvc 4,Knockout.js,我正在尝试使用ASP.NETMVC4和KnockoutJS为数据记录创建一个单页编辑器。它非常简单,有一个显示记录的表和一个编辑单个记录的表单 单击“编辑”编辑记录时,表单将更新,数据将毫无问题地保留到数据库中。这之后有两个问题: 保存后,正在编辑的记录不会在表中更新(即,观察值不会更新) 保存后,包含正在编辑的记录的控件不清除 我不知道如何解决(1)。对于(2),是否有某种方法可以编写一个泛型扩展方法或函数,以便在Knockout完成后清除任何表单。我可以很容易地用JQuery完成它,但我可能
@model IEnumerable<SiteDto>
@{
ViewBag.Title = "Index";
}
<h2>Sites</h2>
<table>
<caption>Sites</caption>
<thead>
<tr>
<th>Name</th>
<th>Link</th>
<th>Url</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: sites">
<tr>
<td><span data-bind="text: id"></span></td>
<td><span data-bind="text: name"></span></td>
<td><span data-bind="text: url"></span></td>
<td><button data-bind="click: $parent.selectItem">Edit</button></td>
</tr>
</tbody>
</table>
<div data-bind="with: selectedItem">
<table>
<caption data-bind="text: name"></caption>
<tbody>
<tr>
<td><input data-bind="value: id" /></td>
</tr>
<tr>
<td><input data-bind="value: url" /></td>
</tr>
<tr>
<td><input data-bind="value: name" /></td>
</tr>
</tbody>
</table>
<button data-bind="click: save">Save</button>
</div>
<script type="text/javascript">
function viewModel() {
var sites = ko.observableArray(@Html.Raw(Model.ToJson()));
var selectedItem = ko.observable();
selectItem = function (s) {
selectedItem(s);
};
save = function () {
alert(ko.toJSON(selectedItem));
$.ajax({
url: "/Home/Save",
type: "POST",
data: ko.toJSON(selectedItem),
contentType: "application/json",
dataType: "json",
success: function(result) {
alert(result);
},
error: function() {
alert("fail");
}
});
};
return {
sites: sites,
selectedItem: selectedItem,
selectItem: selectItem,
save: save
}
}
ko.applyBindings(viewModel);
</script>
@model IEnumerable
@{
ViewBag.Title=“Index”;
}
地点
地点
名称
链接
网址
编辑
拯救
函数viewModel(){
var sites=ko.observearray(@Html.Raw(Model.ToJson());
var selectedItem=ko.observable();
选择项=功能{
选择编辑项;
};
save=函数(){
警报(ko.toJSON(selectedItem));
$.ajax({
url:“/Home/Save”,
类型:“POST”,
数据:ko.toJSON(selectedItem),
contentType:“应用程序/json”,
数据类型:“json”,
成功:功能(结果){
警报(结果);
},
错误:函数(){
警报(“失败”);
}
});
};
返回{
地点:地点,,
selectedItem:selectedItem,
selectItem:selectItem,
保存:保存
}
}
应用绑定(视图模型);
我会一次回答你的一个问题,因为它们并不真正相关
1) 这里的问题是,您将ASP.NETMVC模型放在一个可观察的环境中。问题是,如果项目被添加、删除或交换,observableArray将更新UI,但它不会通知UI对单个项目的更改。因此,即使您确实正确地编辑了行,UI也永远不会知道。理想的解决方案不是简单地将MVC模型注入到observableArray中,而是将模型映射到一个数据结构,在该数据结构中,项的可编辑属性(id、url、名称)是可观察的。未经测试的演示代码:
var rawSites = @Html.Raw(Model.ToJson()),
sites = ko.observableArray(rawSites.map(function (rawSite) {
return {
id: ko.observable(rawSite.id),
url: ko.observable(rawSite.url),
name: ko.observable(rawSite.name)
};
}));
编辑:我最初的回答建议了第二种方法,即通过从ObservalArray中删除编辑的项并重新添加来“黑客”UI更新@Tomalak在评论中提出了一个更好的建议:对项目使用valueHasMutated()
。结果是一样的,但它的黑客性要小得多。请注意,在我看来,上述解决方案仍然更可取,因为它将执行得更好(需要的UI回流更少),并且当您稍后向该代码添加更多功能时,它会更加健壮
2) 这取决于你想要什么。您希望编辑表单保持可见还是消失?您已经在使用带有:selectedItem绑定的,这使得消失行为非常简单:只需从保存成功回调调用selectItem(null)
。如果您希望表单始终可见,只需清除字段,我想以下方法可以奏效:
function viewModel() {
var sites = ko.observableArray(@Html.Raw(Model.ToJson()));
var originalItem = null;
var selectedItem = {
id: ko.observable(),
url: ko.observable(),
name: ko.observable()
};
var selectItem = function (s) {
// This function now copies the properties instead of using the item itself
selectedItem.id(ko.unwrap(s.id));
selectedItem.url(ko.unwrap(s.url));
selectedItem.name(ko.unwrap(s.name));
// Get a reference to s so we can update it when we are done editing
originalItem = s;
};
var resetSelectedItem = function () {
// Clear the form and reset the reference we held earlier
selectItem({
id: null,
url: null,
name: null
});
originalItem = null;
};
save = function () {
alert(ko.toJSON(selectedItem));
$.ajax({
url: "/Home/Save",
type: "POST",
data: ko.toJSON(selectedItem),
contentType: "application/json",
dataType: "json",
success: function(result) {
alert(result);
// Done editing: update the item we were editing
originalItem.id(selectedItem.id());
originalItem.url(selectedItem.url());
originalItem.name(selectedItem.name());
// Clear the form
resetSelectedItem();
},
error: function() {
alert("fail");
// Clear the form
resetSelectedItem();
}
});
};
return {
sites: sites,
selectedItem: selectedItem,
selectItem: selectItem,
save: save
}
}
我假设您在第一个代码示例中遗漏了一个ko.observable(
。说到丑陋的黑客行为,您可以使用valueHasMutated()
通知订阅者更改,但“不必要的回流”问题仍然存在。制作可观察的数组元素要优雅得多。可以使用单独的子视图模型和映射插件使处理复杂结构更加愉快。对!我编辑了ko.observable(
返回。值发生了变化
确实是一个选项,而且比我建议的更好。我会根据你的建议编辑我的答案。这仍然是一个黑客行为,但比我建议的要少。我个人不喜欢映射插件,所以我不能在这里真正演示它的用法,但它确实是一个受欢迎的插件可以在这里使用。如果你不喜欢“官方”的,还有其他的映射插件。但是,使用一个插件有它的优点,特别是因为你可以轻松地进行局部映射,只更新视图模型中实际更改的部分,从而减少屏幕更新。(更不用说通过数据映射的声明性方法编写更清晰的代码了。)