我正试图将Bootstrap Selectpicker与knockout.js一起使用。已经有一个自定义绑定适用于Selectpicker的多选版本(如图所示),但我需要它来处理单选版本。我原以为它会像将ko.observableArray
更改为ko.observable
并删除multiple
属性一样简单,但事实并非如此。有什么想法可以让它发挥作用吗?
摆弄绑定和我更新的代码
编辑请参阅下面的替代解决方案
问题出在selectPicker.init函数上。
您需要调用选项绑定,而不是值绑定。options.init设置初始内部状态,当绕过options.update函数时,会重置该值。
// regular select and observable so call the default value binding
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor);
更改为
// regular select and observable so call the default value binding
ko.bindingHandlers.options.init(element, valueAccessor, allBindingsAccessor);
编辑
好的,我带您回到了使用标准选项绑定的基础示例,以使正常的选择工作。
然后仅使用selectpicker绑定进行初始化和刷新。它将自行与select同步。
在Knockout 3之前,如果元素上的任何绑定导致更新(如更新选项、值或selectedOptions),则会调用selectPicker更新函数。使用Knockout 3,绑定现在可以独立启动(这是件好事),但您现在需要使用订阅来在选项或值/selectedOptions更改时获得通知。
我想你会看到这现在简单多了,在你的自定义绑定中,单选和多选之间没有区别。如果更新了teamItems或itemID observable,现在就可以工作了。
HTML
<!-- Multiple Select -->
<select data-bind="selectedOptions: teamIDs,
options: teamItems,
optionsText: 'text',
optionsValue : 'id',
selectPicker: {}" multiple="true"></select>
JAVASCRIPT
ko.bindingHandlers.selectPicker = {
after: ['options'], /* KO 3.0 feature to ensure binding execution order */
init: function (element, valueAccessor, allBindingsAccessor) {
var $element = $(element);
$element.addClass('selectpicker').selectpicker();
var doRefresh = function() {
$element.selectpicker('refresh');
}, subscriptions = [];
// KO 3 requires subscriptions instead of relying on this binding's update
// function firing when any other binding on the element is updated.
// Add them to a subscription array so we can remove them when KO
// tears down the element. Otherwise you will have a resource leak.
var addSubscription = function(bindingKey) {
var targetObs = allBindingsAccessor.get(bindingKey);
if ( targetObs && ko.isObservable(targetObs )) {
subscriptions.push( targetObs.subscribe(doRefresh) );
}
};
addSubscription('options');
addSubscription('value'); // Single
addSubscription('selectedOptions'); // Multiple
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
while( subscriptions.length ) {
subscriptions.pop().dispose();
}
} );
},
update: function (element, valueAccessor, allBindingsAccessor) {
}
};
Knockout对计算绑定(例如item().children.length > foo().maxChildren
)提供了出色而强大的支持,而当前的答案无法支持这些。
因此,为了进一步改进RobertSlanley的回答,并基于Knockout的文档,我创建了以下绑定。
Knockout将自己处理可观察的订阅,只要我们在更新方法中访问它们。这意味着我们可以消除订阅漏洞,只专注于我们真正想做的事情:
ko.bindingHandlers.selectPicker = {
after: ['options', 'value', 'selectedOptions'],
init: function (element, valueAccessor, allBindingsAccessor) {
$(element).addClass('selectpicker').selectpicker();
},
update: function (element, valueAccessor, allBindingsAccessor) {
/* KO 3.3 will track any bindings we depend on
and call us when any of them changes */
allBindingsAccessor.get('options');
allBindingsAccessor.get('value');
allBindingsAccessor.get('selectedOptions');
$(element).selectpicker('refresh');
}
};
这是一个演示小提琴
不幸的是,我还不能对上面的答案发表评论,但HTML部分有一个小错误:
所选的值绑定应该是selectedOptions
,而不是selectOptions
。
HTML
<!-- Multiple Select -->
<select data-bind="selectedOptions: teamIDs,
options: teamItems,
optionsText: 'text',
optionsValue : 'id',
selectPicker: {}" multiple="true"></select>