我用 MVC4、jQuery 和 Twitter Boostrap 开发了一个网站。现在我决定在一些页面上添加敲除,以使工作流程更加流畅。在这个特定页面上,目的是在左侧有一个项目列表,可以使用 jQuery UI 可排序项目重新排序。单击后,每个项目的详细信息将出现在右侧的区域中以进行编辑。根据类型,编辑会非常不同,所以我决定根据类型设置单独的 DIV 标签。
以前的工作版本通过模型加载页面项目。我的想法是在淘汰视图模型中添加一个可观察数组,然后在页面加载时加载它。该模型是在服务器上定义的,因此我的意图是不再在客户端视图模型上定义所有属性。进一步的操作和编辑将只使用相同的集合并通过 AJAX 调用将新的/更改的/删除的值上传到服务器。
我已经阅读了淘汰演示并在 stackoverflow 中搜索了类似的用例。我想我遵循了这些建议,但显然缺少一些东西。模型加载正常。项目出现并根据类型以不同的颜色显示。它们是可排序的,并且在使用时,更改会被发送回服务器并保持不变。
缺少的部分是当前选中项的显示和编辑。我在视图模型中添加了另一个名为 currentItem 的属性。在函数 $("body").on("click", ".sortableItem" 中,我可以验证 currentItem 是否已加载并且 Heading 属性是否正确。
但 DIV divEditType1 的可见性和内容不受影响。我误解了绑定的概念吗?我是否误解了从服务器 JSON 数组加载?非常感谢任何帮助。
这是服务器页面模型:
public class PresentationItemsModel
{
public Guid PresentationId { get; set; }
public string DisplayName { get; set; }
public List<PresentationItemModel> PresentationItems { get; set; }
}
这是重复项模型:
public class PresentationItemModel
{
public Guid PresentationItemId { get; set; }
public string PresentationItemType { get; set; }
public int OrderNumber { get; set; }
public string Heading { get; set; }
public string Content { get; set; }
....
}
这是客户端页面(删除了无关部分):
@model MyCustomWeb.Models.PresentationItemsModel
<header>
<h2>@Model.DisplayName</h2>
</header>
<div style="float: left;">
<fieldset>
<legend>Current list</legend>
<ul id="sortable" data-bind="foreach: presentationItems">
<li class="sortableItem btn btn-block" data-bind="css: 'sortable' + PresentationItemType + 'Item'">
<div style="font-weight: 500;">
<span data-bind="text: Heading"></span>
<span class="ui-icon ui-icon-arrowthick-2-n-s" style="display: inline-block; color: gray; float: right; opacity: 0.5; height: 14px; margin: 2px 4px 0 0"></span>
</div>
</li>
</ul>
</fieldset>
</div>
<div id="divEditType1" data-bind="visible: currentItem.PresentationItemType == 'Type1'" style="float: left; margin-left: 50px;">
<fieldset>
<legend>Edit Type 1</legend>
<div class="control-group">
<input type="text" data-bind="value: currentItem.Heading" placeholder = "Enter Heading" />
</div>
<div class="control-group">
<button id="btnSave" type="submit" class="btn btn-primary">Save</button>
<button id="btnDelete" type="submit" class="btn btn-danger">Delete</button>
</div>
</fieldset>
</div>
<div id="divEditType2" data-bind="visible: currentItem.PresentationItemType = 'Type2'" style="float: left; margin-left: 50px;">
</div>
<div id="divEditType3" data-bind="visible: currentItem.PresentationItemType = 'Type3'" style="float: left; margin-left: 50px;">
</div>
@section Scripts {
<script>
$(document).ready(function () {
// Enable item sorting
$("#sortable").sortable(
{
cursor: "move",
placeholder: "sortableSeparator",
update: function () {
// Create array of all changed items
var changeItems = [];
var currentOrderNumber = 1;
$(".sortableItem").each(function () {
var id = $(this).attr('data-id');
var previousOrderNumber = $(this).attr('data-orderNumber');
if (currentOrderNumber != previousOrderNumber)
changeItems.push({ "id": id, "orderNumber": currentOrderNumber });
currentOrderNumber += 1;
});
// Send ajax action
$.ajax({
type: "PUT",
url: "/api/PresentationApi/ChangeOrder/" + "@Model.PresentationId",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(changeItems)
});
},
}
);
// Enable change depending on item click
// Note: Must be done this way beacuse of the dynamic binding!
$("body").on("click", ".sortableItem", function () {
viewModel.currentItem = ko.dataFor(this);
alert(viewModel.currentItem.Heading); // Works fine!
//alert(JSON.stringify(viewModel.currentItem)); // Also looks good!
});
// Knockout view model
function ViewModel() {
var self = this;
self.presentationItems = ko.observableArray([]);
self.currentItem = ko.observable();
}
var viewModel = new ViewModel();
viewModel.presentationItems(@Html.Raw(Json.Encode(Model.PresentationItems)));
ko.applyBindings(viewModel);
});
</script>
}
编辑:可以在这里找到创建 Fiddle 演示的尝试:http: //jsfiddle.net/XXNz9/