1

我用 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/

4

1 回答 1

1

I'd recommend you to wrap your "divEditType1" with another div. The context of inner div will change to "currentItem" so you you won't need to write it every time

<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>

This can also solve your problem because your binding can fail if currentItem == null when applied

于 2013-08-19T09:21:44.247 回答