Javascript 选择2 allowclear和knockout.js
我使用select2和knockoutJs进行以下简单绑定:Javascript 选择2 allowclear和knockout.js,javascript,jquery,knockout.js,Javascript,Jquery,Knockout.js,我使用select2和knockoutJs进行以下简单绑定: ko.bindingHandlers.select2 = { init: function (element, valueAccessor, allBindings, viewModel, bindingContext) { var options = ko.toJS(valueAccessor()) || {}; setTimeout(function () { $(e
ko.bindingHandlers.select2 = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var options = ko.toJS(valueAccessor()) || {};
setTimeout(function () {
$(element).select2(options);
}, 0);
}
};
标记:
<select class="select2" style="width:100%" data-bind="optionsCaption: '',options: $root.items,optionsText: 'description',optionsValue: 'id', value: $root.selectedItem,select2: { placeholder: 'Select an item...',allowClear: true }"></select>
但这行不通 有两个问题 1) bindinghandler中的
更新
是基于值更改更新DOM,您永远不应该定义一个能够改变模型的更新
回调
正确的方法是,在定义新的bindinghandler时,使用init
callback将所有change
事件与模型连接起来,update
回调仅仅是一个DOM绘图例程
如果您的init
提供了DOM图形(例如由select2提供),则不需要定义update
回调
因此,行ko.bindingHandlers.value.update(元素,函数(){return';})代码>仅重新绘制DOM,它不会执行您想要的操作
2) 您创建的select2
绑定有一些漏洞
- 首先,
value
binding不知道select2
binding的存在,这正是您需要解决的问题
- 其次,您的
select2
绑定必须等待其他绑定(选项
绑定)完成DOM创建,这就是为什么要使用setTimeout
。但是ko提供了一种定义绑定序列的方法,只需查看ko value
绑定的源代码,它被定义为'after':['options','foreach']
- 第三,select2不会对外部变化做出响应。例如,如果您有另一个UI要更新
$root.selectedItem
(一个普通的选择列表),该UI引发的更改将不会同步回您的select2
解决方案
根据现有的值定义选择2
绑定(刚刚发现不需要),并连接所有更改事件
- 我们不需要
“select2 removed”
事件,这一切都是关于“change”
事件的
选择2
提供所有绘图,我们不需要更新
回调
- 使用标志
shouldIgnore
中断值订阅服务器和select2更改事件处理程序之间的循环
你能用你的代码提供一个JSFIDLE吗setTimeout有什么用?此外,我只能看到“init”实现,如果您有一个“update”实现,是否也可以在bindingHandler中显示您的“update”实现?要遵循ko实践,changeListener的内容应该转到valueSelect2.update
callback。
setTimeout(function () {
$(element).select2(options).on("select2-removed", function (e) {
ko.bindingHandlers.value.update(element, function () { return ''; });
});
...
ko.bindingHandlers.valueSelect2 = {
'after': ['options'],
'init': function(element, valueAccessor, allBindings) {
// kind of extend value binding
// ko.bindingHandlers.value.init(element, valueAccessor, allBindings);
var options = allBindings.get('select2Options') || {};
$(element).select2(options);
var value = valueAccessor();
// init val
$(element).val(ko.unwrap(value)).trigger("change");
var changeListener;
if (ko.isObservable(value)) {
var shouldIgnore = false;
changeListener = value.subscribe(function(newVal) {
if (! shouldIgnore) {
shouldIgnore = true;
// this is just select2 syntax
$(element).val(newVal).trigger("change");
shouldIgnore = false;
}
});
// this demo only works on single select.
$(element).on("change", function(e) {
if (! shouldIgnore) {
shouldIgnore = true;
if (e.val == '') {
// select2 use empty string for unselected value
// it could cause problem when you really want '' as a valid option
value(undefined);
} else {
value(e.val);
}
shouldIgnore = false;
}
});
}
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
if (changeListener) changeListener.dispose();
$(element).select2("destory");
});
}
};