0

大家好,

我将 Knockoutjs 与 Jquery UI 小部件结合使用,以显示一个自动完成框,其中每个选定项目具有多个跨度。

我正在遵循以下方法

1)在视图模型中有一个可观察的数组(selecteditems)并将其绑定到声明性模板以显示 SPAN

2) 绑定到 JQUERY UI 自动完成小部件以显示建议的输入框,并在每次选择时使用 CustomBindingHandler 将新项目添加到 selecteditems 数组。

3) 使用 CustomBindingHandler 向绑定到可观察数组 selecteditems 的每个 SPAN 显示 JQUERY UI ToolTip 小部件。

问题 - 我面临的是 JQUERY UI ToolTip 小部件在加载中显示没有任何问题,但是只要 selecteditems 数组发生更改,在 CustomBindingHandler 中就无法识别 Tooltip 小部件

任何帮助将不胜感激。

<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 Tooltip 小部件的 API 文档表明,工具提示逻辑旨在绑定到容器而不是单个元素。

例如,要在纯 jQuery 中为所有内容获取工具提示<li><ul>您可以这样做:

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

主要优点是当容器的子项更改时,您不需要绑定/取消绑定/更新任何工具提示逻辑。另一个优点是这减少了页面的负载,因为它只注册一个工具提示而不是几个工具提示。


您可以(并且应该!)使用这种方法,因为它完全符合您的要求。您有一个容器,其中包含可变数量的子项,这些子项都应该显示一个工具提示,其中包含根据相同逻辑构建的内容。

由于我们绑定到容器,我们需要在容器的视图模型上使用一个小型代理函数来为我们检索单独的工具提示文本。

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