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