javascript - 複雑なデータとオートコンプリートに関するバインドの問題

原文 javascript jquery knockout.js

Knockout JS 3.2を使用していますが、オートコンプリートドロップダウンで使用したいと思います。 2つの問題を回避することはできません。

これをスタンドアロンで実行できるように、データとコードを簡略化しました。

<script type="text/javascript">
    var data = [
            { "User": { "Id": 1, "DisplayName": "john a" }, "Roles": [{ "Id": 1, "Name": "admins" }, { "Id": 2, "Name": "users" }] },
            { "User": { "Id": 2, "DisplayName": "john b" }, "Roles": [] },
            { "User": { "Id": 3, "DisplayName": "john c" }, "Roles": [{ "Id": 1, "Name": "admins" }] },
            { "User": { "Id": 4, "DisplayName": "john d" }, "Roles": [] },
            { "User": { "Id": 5, "DisplayName": "john e" }, "Roles": [{ "Id": 2, "Name": "users" }] }
    ];

    $(function () {
        $("#searchTerm").autocomplete({
            source: data,
            minLength: 1,
            select: function (event, ui) {
                if (ui.item) {
                    var viewModel = ko.mapping.fromJS(ui.item);
                    ko.cleanNode($("#userDetails")[0]);
                    ko.applyBindings(viewModel, $("#userDetails")[0]);
                }
            }
        })
        .autocomplete("instance")._renderItem = function (ul, item) {
            return $("<li>")
              .append("<a>" + item.User.DisplayName + "</a>")
              .appendTo(ul);
        };
    });
</script>


<div>Select User: <input id="searchTerm" name="searchTerm" type="text" /></div>

<div id="userDetails">
    <div>User: <span data-bind="text: User.DisplayName"></span></div>
    <div data-bind="foreach: Roles, visible: Roles().length > 0">
        <div><span data-bind="text: Name"></span></div>
    </div>
</div>


問題:


userDetails divがバインドされている場合にのみ表示し、ページの読み込み時に非表示にします。 style="display:none"を設定してから、data-bind="if:User"またはdata-bind="if:User.Id"を設定してみました。表示属性を設定すると、ロード時に要素が非表示になりますが、バインド時に変更されません。
Roles要素のバインディングが正しく機能しません。そのユーザーが初めて選択されたとき、役割は表示されますが、ユーザーの選択を変更した後は表示されません。
答え
常に再バインドする代わりに、selectedUserプロパティを持つ適切なビューモデルを用意し、automcompleteハンドラーでそれを更新する必要があります。

var viewModel = {
    selectedUser: ko.observable()
}

ko.applyBindings(viewModel, $("#userDetails")[0]);

$(function () {
    $("#searchTerm").autocomplete({
        source: data,
        minLength: 1,
        select: function (event, ui) {
            if (ui.item) {
                var user = ko.mapping.fromJS(ui.item);
                viewModel.selectedUser(user);                                       
            }
        }
    })
    .autocomplete("instance")._renderItem = function (ul, item) {
        return $("<li>")
          .append("<a>" + item.User.DisplayName + "</a>")
          .appendTo(ul);
    };
});


このアプローチでは、with bindingを使用でき、両方の問題を解決します。

<div id="userDetails" data-bind="with: selectedUser">
    <div>User: <span data-bind="text: User.DisplayName"></span></div>
    <div data-bind="foreach: Roles, visible: Roles().length > 0">
        <div><span data-bind="text: Name"></span></div>
    </div>
</div>


デモJSFiddle
関連記事

javascript - Angular検索と結果ビューを切り替えてデータを渡す方法

javascript - RubyコードでJqueryを介してクリックをトリガーする

javascript - 内部のng-transcludeからのAngularJS親ディレクティブスコープ

javascript - 移行が機能しない

javascript - JavaScriptキャンバスタグとストロークテキストメソッド

javascript - ユーザー入力-JavaScriptノードjs

javascript - Element.prop( 'scrollHeight')は、Angular.jsの異なるリストアイテムに対して同じ値を返します

javascript - サードパーティのWebブラウザーでiOS8アクション拡張機能をホストする方法

javascript - jQueryは、上からクラス名でDIVを選択します

javascript - push.applyを使用して、ノックアウトがJavaScriptオブジェクトとどのように相互作用するかを理解する