Search code examples
knockout.jscustom-bindingbootstrap-switch

How to call a knockout function with bootstrap-switch.js binding?


I'm trying to show my data in a table but instead of checkbox show something fancy like http://www.bootstrap-switch.org/

I've managed to build my table and handle the plugin using this binding

ko.bindingHandlers.bootstrapSwitchOn = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        $elem = $(element);
        $(element).bootstrapSwitch();
        $(element).bootstrapSwitch('state', ko.utils.unwrapObservable(valueAccessor())); // Set intial state
        $elem.on('switchChange.bootstrapSwitch', function (e, data) {
            valueAccessor()(data);
            //$(this).trigger('click'); --***--
        }); // Update the model when changed.
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var vStatus = $(element).bootstrapSwitch('state');
        var vmStatus = ko.utils.unwrapObservable(valueAccessor());
        if (vStatus != vmStatus) {
            $(element).bootstrapSwitch('state', vmStatus);
        }
    }
};

I've showed the data but I'm stuck in the next phase. I want to call a Method to change the state of my data in DB every time a user clicks on the switch. This is what I tried

<input type="checkbox" data-on-color="success" data-on-text="on" data-off-text="off" data-off-color="danger" name="switch-checkbox" 
             data-bind="bootstrapSwitchOn: active, click: $root.updateData"></td>

However the The method is never called. As I understand this is because bootstrap-switch.js doesn't actually triggers it. SO I tried to do it myself see --*-- in custom binding. This has resulted in triggering the event 2 times. Which is not acceptable.

Is there any way to call this method in knockout but without changing VM? I know I can use a dummyObservable and update it in my binding but what is the point of custom binding if I have to change every VM I want to use the bootstrap-switch on?

Basically I'm trying to make something reusable, and stuck in knockout part.


Solution

  • I found a solution for my problem. At the end I went the other way and called the function I needed from VM directly in my bindinng

    ko.bindingHandlers.bootstrapSwitchOn = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            $elem = $(element);
            $elem.bootstrapSwitch();
            $elem.bootstrapSwitch('state', ko.utils.unwrapObservable(valueAccessor().state())); // Set intial state
            $elem.on('switchChange.bootstrapSwitch', function (e, data) {
                var context = ko.contextFor(this);
                context.$root[valueAccessor().fnctn](context.$data);
            });
        }
    };
    

    My HTML now looks different as I want to be as generic as possible so I'm passing the parameter to binding to know which function of VM to call.

    <input type="checkbox" data-on-color="success" data-on-text="on" data-off-text="off" data-off-color="danger" name="switch-checkbox" 
             data-bind="bootstrapSwitchOn: {state: active, fnctn: 'updateData' }"></td>