0

こんにちは、みんな、

Knockoutjs を Jquery UI ウィジェットと組み合わせて使用​​し、選択した項目ごとに複数のスパンを持つオートコンプリート ボックスを表示しています。

私は以下のアプローチに従っています

1) ビューモデルには、監視可能な配列 (selecteditems) があり、それを宣言型テンプレートにバインドして SPAN を表示します。

2) 提案を表示する JQUERY UI オートコンプリート ウィジェットにバインドされた入力ボックス。選択ごとに、CustomBindingHandler を使用して、selecteditems 配列に新しい項目を追加します。

3) CustomBindingHandler を使用して、オブザーバブル配列の選択項目にバインドされている各 SPAN に JQUERY UI ToolTip ウィジェットを表示します。

問題-私が直面しているのは、JQUERY UI ToolTip ウィジェットがロード時に問題なく表示されることですが、selecteditems 配列に変更があるたびに、Tooltip ウィジェットが CustomBindingHandler で認識されません。

どんな助けでも大歓迎です。

<div>

    <div style="max-height: 105px;" data-bind="foreach: selectedItems">

        <span data-bind="text: name, id: id, assignToolTip: id"></span>

        <input data-bind="assignAutoComplete: { rootVm: $root }" type="email" value="">
    </div>

</div>

<script>

    var MyViewModel = function () {
        this.selectedItems = ko.observableArray(
            [{ name: "eww", id: "ww" },
                { name: "aa", id: "vv" },
                { name: "xx", id: "zz" }]);
    };

    ko.bindingHandlers.assignToolTip = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
            if ($(element) != undefined) {
                var currentDataItem = ko.dataFor(element);
                $(element).tooltip({
                    items: 'span',
                    track: true,
                    content: function () {

                        return "<ul><li>" + currentDataItem.name + "</li><li>" + currentDataItem.id + "</li></ul>";
                    }
                });
            }
        },

    };

    ko.bindingHandlers.assignAutoComplete = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
            if ($(element) != undefined) {
                var currentDataItem = ko.dataFor(element);
                $(element).autocomplete({
                    source: function (request, response) {
                        $.ajax({
                            url: "http://ws.geonames.org/searchJSON",
                            dataType: "jsonp",
                            data: {
                                featureClass: "P",
                                style: "full",
                                maxRows: 12,
                                name_startsWith: request.term
                            },
                            success: function (data) {

                                response($.map(data.geonames, function (item) {
                                    return {
                                        label: item.name + (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
                                        value: item.name
                                    };
                                }));
                            }
                        });
                    },
                    minLength: 2,
                    select: function (event, ui) {
                        var settings = valueAccessor();
                        var rootVm = settings.rootVm;
                        rootVm.selectedItems.push({ name: ui.item.label, id: ui.item.label });
                        return false;
                    },
                    open: function () {
                        $(this).removeClass("ui-corner-all").addClass("ui-corner-top");
                    },
                    close: function () {
                        $(this).removeClass("ui-corner-top").addClass("ui-corner-all");
                    }
                });
            }
        }
    };


    ko.applyBindings(new MyViewModel());
</script>
<script src="~/Scripts/jquery-ui-1.10.3.js"></script>
4

2 に答える 2

0

jQuery UIツールチップ ウィジェットの API ドキュメントは、ツールチップ ロジックが個々の要素ではなくコンテナにバインドされることを意図していることを示唆しています。

たとえば、純粋な jQuery ですべてのツールチップを取得するには<li>、次の<ul>ようにします。

$("ul").tooltip({
    items: "li",
    content: function () {
        return "tooltip text for this element";
    }
});

主な利点は、コンテナーの子が変更されたときに、ツールヒント ロジックをバインド/バインド解除/更新する必要がないことです。もう 1 つの利点は、複数のツールチップではなく 1 つのツールチップのみが登録されるため、ページの負荷が少なくなることです。


このアプローチは要件に完全に適合するため、このアプローチを使用できます (使用する必要があります)。同じロジックの後に構築されたコンテンツを含むツールチップをすべて表示する必要がある可変数の子を持つコンテナーがあります。

コンテナーにバインドするため、個々のツールヒント テキストを取得するには、コンテナーのビュー モデルに小さなプロキシ関数が必要です。

HTML テンプレート:

<div data-bind="
    foreach: items, 
    tooltip: {items: 'label', content: tooltipContentProxy}
">
    <div>
        <label data-bind="text: name, attr: {for: id}"></label>
        <input data-bind="attr: {id: id}, value: inputVal, valueUpdate: 'keyup'" type="text" />
    </div>
</div>

tooltipカスタム バインディング ハンドラー:

ko.bindingHandlers.tooltip = {
    init: function (element, valueAccessor) {
        var options = ko.unwrap(valueAccessor());
        $(element).tooltip(options);
    }
};

私たちがどのように

  • バインディングですべてのツールチップ オプションを便利に構成できます
  • ビューまたはビュー モデルに依存関係がない
  • updateこのセットアップはデータの変更から切り離されているため、ハンドラーも必要ありません

そして最後にビューモデル:

function Item(data) {
    var self = this;

    self.id = ko.observable(data.id);
    self.name = ko.observable(data.name);
    self.inputVal = ko.observable(""); 
    self.tooltipText = ko.computed(function () {
        var escapedVal = $("<div>", {text: self.inputVal()}).html();
        return "Hi! My value is '" + escapedVal + "'.";
    });
}

function ViewModel() {
    var self = this;

    self.items = ko.observableArray([/* Item objects here ...*/]);

    self.tooltipContentProxy = function () {
        var targetItem = ko.dataFor(this);
        return targetItem.tooltipText();
    };
}

ツールチップが正しく表示されるようになりました。http://jsfiddle.net/7TqpK/

于 2013-10-24T13:37:09.697 に答える
0

配列内の値が変更されたときにツールチップを更新しようとしている場合は、配列内のオブジェクトの値を観察できるように、これを少し変更する必要があります。

var SelectedItem = function(obj){
    var self = this;
    self.name = ko.observable(obj.name);
    self.id = ko.observable(obj.id);
    self.tooltipText = ko.computed(function(){
        return "<ul><li>" + self.name() + "</li><li>" + self.id() + "</li></ul>";
    });
    return self;
};

var MyViewModel = function () {
    var self = this;
    self.selectedItems = ko.observableArray(
        [new SelectedItem({ name: "eww", id: "ww" }),
            new SelectedItem({ name: "aa", id: "vv" }),
            new SelectedItem({ name: "xx", id: "zz" })]);
    return self;
};

それが完了したら、更新を処理するために customBinding を更新する必要があります。

ko.bindingHandlers.assignToolTip = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        if ($(element) != undefined) {                
            var currentDataItem = ko.dataFor(element);
            $(element).tooltip({
                items: 'span',
                track: true,
                content: function () {
                    return currentDataItem.tooltipText();
                }
            });
        }
    },
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext){            
        if ($(element) != undefined) {                
            $(element).tooltip( "destroy" );
            var currentDataItem = ko.dataFor(element);
            $(element).tooltip({
                items: 'span',
                track: true,
                content: function () {
                    return currentDataItem.tooltipText();
                }
            });
        }
    }
};

必要な最後の変更は、監視可能な配列にプッシュするときはいつでも、SelectedItemオブジェクトのインスタンスにする必要があることです。

select: function (event, ui) {
    var settings = valueAccessor();
    var rootVm = settings.rootVm;
    rootVm.selectedItems.push(
        new SelectedItem({ name: ui.item.label, id: ui.item.label })
    );
    return false;
},

作業例: http://jsfiddle.net/infiniteloops/PLYKk/

于 2013-10-23T10:01:39.563 に答える