敲除绑定不起作用

时间:2013-08-19 08:42:00

标签: jquery asp.net-mvc-4 binding knockout.js

我开发了一个包含MVC4,jQuery和Twitter Boostrap的网站。现在我决定在某些页面添加knockout,以使工作流程更流畅。在此特定页面上,目的是在左侧有一个项目列表,可以使用jQuery UI可排序项目重新排序。单击时,每个项目的详细信息将在右侧区域中进行编辑。根据类型的不同,编辑将会有很大差异,因此我决定根据类型设置单独的DIV标签。

之前的工作版本通过模型加载页面项。我的想法是在knockout viewmodel中添加一个observable数组,然后在页面加载时加载它。该模型在服务器上定义,因此我的目的是不再在客户端视图模型上定义所有属性。进一步的操作和编辑只会使用相同的集合,并通过AJAX调用将新的/更改/删除的值上传到服务器。

我已经阅读了淘汰演示并搜索了类似用例的stackoverflow。我想我遵循了这些建议,但显然缺少了一些东西。模型加载好了。项目出现并根据类型显示不同的颜色。它们是可排序的,并且随时可以将更改发送回服务器并保持正常。

缺少的部分是显示和编辑当前所选项目。我在viewmodel中添加了另一个名为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>
}

编辑: 可以在此处找到创建小提琴演示的尝试: http://jsfiddle.net/XXNz9/

1 个答案:

答案 0 :(得分:1)

我建议你用另一个div包装你的“divEditType1”。内部div的上下文将更改为“currentItem”,因此您不需要每次都写入

<div data-bind="with: currentItem">
    <div id="divEditType1" data-bind="visible: PresentationItemType = 'Type1'" style="float: left; margin-left: 50px;">
        <fieldset>
            <legend>Edit Type 1</legend>
            <div class="control-group">
                <input type="text" data-bind="value: 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>

这也可以解决您的问题,因为如果在应用currentItem == null时您的绑定可能会失败