我将bootstrap-switch与从这个问题中引用的敲除绑定处理程序一起使用,如下所示:
ko.bindingHandlers.bootstrapSwitchOn = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
$elem = $(element);
$elem.bootstrapSwitch();
// Set intial state
$elem.bootstrapSwitch('setState', ko.utils.unwrapObservable(valueAccessor()));
$elem.on('switch-change', function (e, data) {
// Update the model when changed.
valueAccessor()(data.value);
});
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var vStatus = $(element).bootstrapSwitch('status');
var vmStatus = ko.utils.unwrapObservable(valueAccessor());
if (vStatus != vmStatus) {
$(element).bootstrapSwitch('setState', vmStatus);
}
}
};
这似乎工作得很好,我已经模拟了一个小提琴来说明我如何在这里使用它:
http://jsfiddle.net/swervo/of0q42j0/5/
但是,我有一些问题似乎无法以令人满意的方式解决:
1)如果我在 ko.observable 数组中有一个项目数组,我可以在所有项目上放置一个点击处理程序,并让它们在父视图模型中调用一个函数,如下所示:
data-bind="click: $parent.clickHandler"
调用时,它会通过项目自己的视图模型。这对于获取被点击项目的属性非常方便,例如,id。我在上面的小提琴中放了一个按钮来说明这是多么容易。
但是,如果我使用引导开关而不是简单的按钮,则开关似乎不知道它的父级,并且我找不到将包含开关的视图模型传递到其父级的优雅方式——比如你可以用一个按钮。我尝试为数组中的每个项目提供对其父视图模型的引用,这确实有效,但会创建循环引用,因此似乎不是正确的方法。
2)在我正在构建列表中项目状态的应用程序中,可以在不同的客户端上更改 - 本地状态需要更新以反映这些远程客户端。同样,也可以在本地客户端上更改状态,然后将其传播到其他客户端。我的问题是如何区分本地发生的状态更改(即,由于用户单击开关)和远程发生的更改(即,由于来自服务器的更新)。在我的实际项目中,我使用敲除订阅来监听链接到开关的值的变化,如下所示:
viewModel.observableValue.subscribe(function(newValue) {
// test value on server and if it is different update
});
当我的开关更改以反映新状态时,我想避免从服务器接收更新然后再次更新服务器(具有相同的状态)。目前,我通过在发送更新之前测试服务器状态(如上面的代码片段中所暗示的那样)来解决此问题,如果它与挂起状态更新相同,我将丢弃它。(我已经使用上面引用的小提琴中的按钮模拟了服务器更新)。
我对这些问题的解决方案都不优雅,因此这里提出了问题。任何帮助将非常感激。