Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Twitter bootstrap 3 Modal with knockout

I am trying to fully bind twitter bootstrap modal with knockout. By fully bind I mean that I want every close interaction with modal dialog to work with knockout. I have seen some of the questions, which partially bind them (for example this one does not allow esc).

I am using almost identical binding (which I actually found elsewhere)

ko.bindingHandlers.modal = {
    init: function (element, valueAccessor) {
        $(element).modal({
            show: false
        });
    },
    update: function (element, valueAccessor) {
        var value = valueAccessor();
        if (ko.utils.unwrapObservable(value)) {
            $(element).modal('show');
        } else {
            $(element).modal('hide');
        }
    }
}

But the problem is that not everything work in my Fiddle. As you see if you close Modal with Close button, you can fire this modal again. But if you close it with Esc key, or with clicking on background, or on the X button, you can not open Modal again.

I know that the problem is due to the fact that when I close modal with other means (it is not changing observable and therefore when I fire it for the second time - nothing changes). But I can not figure out how to do this properly.

Here is my hack :-), where everything works. I am giving new value each time. But is there a better way?

like image 755
Salvador Dali Avatar asked Mar 28 '14 07:03

Salvador Dali


2 Answers

bootstrap modal provided events, you just need to hook up event 'hidden.bs.modal'.

BTW, do proper disposal too. http://jsfiddle.net/C8w8v/377/

ko.bindingHandlers.modal = {
    init: function (element, valueAccessor) {
        $(element).modal({
            show: false
        });

        var value = valueAccessor();
        if (ko.isObservable(value)) {
            // Update 28/02/2018
            // Thank @HeyJude for fixing a bug on
            // double "hide.bs.modal" event firing.
            // Use "hidden.bs.modal" event to avoid
            // bootstrap running internal modal.hide() twice.
            $(element).on('hidden.bs.modal', function() {
               value(false);
            });
        }

        // Update 13/07/2016
        // based on @Richard's finding,
        // don't need to destroy modal explicitly in latest bootstrap.
        // modal('destroy') doesn't exist in latest bootstrap.
        // ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
        //    $(element).modal("destroy");
        // });

    },
    update: function (element, valueAccessor) {
        var value = valueAccessor();
        if (ko.utils.unwrapObservable(value)) {
            $(element).modal('show');
        } else {
            $(element).modal('hide');
        }
    }
}
like image 156
huocp Avatar answered Nov 18 '22 03:11

huocp


slightly neater BS binding code - and classes are added when needed.:

ko.bindingHandlers.BSModal= {
    init: function (element, valueAccessor) {
        var value = valueAccessor();
        $(element).addClass('modal').addClass('fade').modal({ keyboard: false, show: ko.unwrap(value) });;
    },
    update: function (element, valueAccessor) {
         var value = valueAccessor();
         ko.unwrap(value) ? $(element).modal('show') : $(element).modal('hide');
    }
};

Then just data-bind="BSModal: true/false Observable" value.

like image 2
Piotr Stulinski Avatar answered Nov 18 '22 02:11

Piotr Stulinski