最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why is my BootstrapSwitch not working in a knockout table built using a foreach - Stack Overflow

programmeradmin4浏览0评论

I'm trying to replace a checkbox in a table with this good looking bootstrap switch.

I'm also using knockout and the binding handler as suggested by this link.

However I cannot get the binding handler to work and or the switch to be clickable in the table built using a knockout for each.

I've replicated the issue in a jsfiddle.

I'm still learning javascript and knockout and just cannot figure out what's going wrong in the binding handler or switch.

Any ideas?

The Html:

<div>
<input type="checkbox" data-bind="checked: on" />
</div>
<div>
    <span data-bind="text: on() ? 'on' : 'off'"></span>
</div>
<div class="switch switch-large" data-bind="bootstrapSwitchOn: on">
    <input type="checkbox" />
</div>

<p>Why doesn't this work in a table?</p>

<table class="table table-striped table-condensed table-bordered">
    <thead>
    <tr>
        <th>Name</th>
        <th>Old</th>
        <th>Old toggle With CheckBox</th>
        <th>Old toggle With Switch</th>
    </tr>
    </thead>
    <tbody data-bind="foreach: items">
        <tr>
            <td data-bind="text: Name"></td>
            <td data-bind="text: Old"></td>
            <td>
                <input type="checkbox" data-bind="checked: Old" />
            </td>
            <td>
                <div class="switch switch-large" data-bind="bootstrapSwitchOn: Old">
                    <input type="checkbox" />
                </div>
            </td>
        </tr>
    </tbody>
</table>

The binding handler and knockout view

/**
 * Knockout binding handler for bootstrapSwitch indicating the status
 * of the switch (on/off): 
 */
ko.bindingHandlers.bootstrapSwitchOn = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        $elem = $(element);
        $(element).bootstrapSwitch('setState', ko.utils.unwrapObservable(valueAccessor())); // Set intial state
        $elem.on('switch-change', function (e, data) {
            valueAccessor()(data.value);
        }); // Update the model when changed.
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var vStatus = $(element).bootstrapSwitch('status');
        var vmStatus = ko.utils.unwrapObservable(valueAccessor());
        if (vStatus != vmStatus) {
            $(element).bootstrapSwitch('setState', vmStatus);
        }
    }
};

var vm = {
    on: ko.observable(true),

    items: ko.observableArray([
        {Name: "Dave", Old: ko.observable(false)},
        {Name: "Richard", Old: ko.observable(true)},
        {Name: "John", Old: ko.observable(false)}
    ])    
}

ko.applyBindings(vm);

I'm trying to replace a checkbox in a table with this good looking bootstrap switch.

I'm also using knockout and the binding handler as suggested by this link.

However I cannot get the binding handler to work and or the switch to be clickable in the table built using a knockout for each.

I've replicated the issue in a jsfiddle.

I'm still learning javascript and knockout and just cannot figure out what's going wrong in the binding handler or switch.

Any ideas?

The Html:

<div>
<input type="checkbox" data-bind="checked: on" />
</div>
<div>
    <span data-bind="text: on() ? 'on' : 'off'"></span>
</div>
<div class="switch switch-large" data-bind="bootstrapSwitchOn: on">
    <input type="checkbox" />
</div>

<p>Why doesn't this work in a table?</p>

<table class="table table-striped table-condensed table-bordered">
    <thead>
    <tr>
        <th>Name</th>
        <th>Old</th>
        <th>Old toggle With CheckBox</th>
        <th>Old toggle With Switch</th>
    </tr>
    </thead>
    <tbody data-bind="foreach: items">
        <tr>
            <td data-bind="text: Name"></td>
            <td data-bind="text: Old"></td>
            <td>
                <input type="checkbox" data-bind="checked: Old" />
            </td>
            <td>
                <div class="switch switch-large" data-bind="bootstrapSwitchOn: Old">
                    <input type="checkbox" />
                </div>
            </td>
        </tr>
    </tbody>
</table>

The binding handler and knockout view

/**
 * Knockout binding handler for bootstrapSwitch indicating the status
 * of the switch (on/off): https://github./nostalgiaz/bootstrap-switch
 */
ko.bindingHandlers.bootstrapSwitchOn = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        $elem = $(element);
        $(element).bootstrapSwitch('setState', ko.utils.unwrapObservable(valueAccessor())); // Set intial state
        $elem.on('switch-change', function (e, data) {
            valueAccessor()(data.value);
        }); // Update the model when changed.
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var vStatus = $(element).bootstrapSwitch('status');
        var vmStatus = ko.utils.unwrapObservable(valueAccessor());
        if (vStatus != vmStatus) {
            $(element).bootstrapSwitch('setState', vmStatus);
        }
    }
};

var vm = {
    on: ko.observable(true),

    items: ko.observableArray([
        {Name: "Dave", Old: ko.observable(false)},
        {Name: "Richard", Old: ko.observable(true)},
        {Name: "John", Old: ko.observable(false)}
    ])    
}

ko.applyBindings(vm);
Share Improve this question asked Sep 16, 2013 at 10:26 DaveDave 3174 silver badges11 bronze badges 1
  • @AndreyNelubin Please read the question thoroughly. – badsyntax Commented Sep 16, 2013 at 12:26
Add a ment  | 

2 Answers 2

Reset to default 2

You were using an older version of bootstrapSwitch (1.3) which automatically executes the plugin on elements with '.switch' class, giving the impression things were working with the custom binding.

I've updated the plugin to the latest version, and am initiating the plugin within the init binding method, eg:

ko.bindingHandlers.bootstrapSwitchOn = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        $elem = $(element);
        $(element).bootstrapSwitch(); // initiate the plugin before setting options
        $(element).bootstrapSwitch('setState', ko.utils.unwrapObservable(valueAccessor())); // Set intial state
        // .. etc
    }
}

Upgrading the latest version of the plugin appears to fix things: https://jsfiddle/badsyntax/59wnW/5/

[UPDATE] - I think the root cause of the issue is a race conditional between the plugin initiating itself on DOM ready, and between knockout building the DOM.

This example works with the old version of bootstrapSwitch, as long as you initiate the plugin after binding the viewmodel: https://jsfiddle/badsyntax/59wnW/6/

Here's the Knockout binding for v3.2.1 of BootstrapSwitch (http://www.bootstrap-switch/):

ko.bindingHandlers.bootstrapSwitchOn = {
  init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
    var $elem;
    $elem = $(element);
    $(element).bootstrapSwitch();
    $(element).bootstrapSwitch("state", ko.utils.unwrapObservable(valueAccessor()));
    $elem.on("switchChange.bootstrapSwitch", function(e, data) {
      valueAccessor()(data);
    });
  },
  update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
    var vStatus, vmStatus;
    vStatus = $(element).bootstrapSwitch("state");
    vmStatus = ko.utils.unwrapObservable(valueAccessor());
    if (vStatus !== vmStatus) {
      $(element).bootstrapSwitch("state", vmStatus);
    }
  }
};
发布评论

评论列表(0)

  1. 暂无评论