KO Bootstrap Popover

by Jorge Bustos Pereda

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-debug.js"></script>
<script src="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css">
<!--<input type="password"  
       data-bind="popover: { 
                  [visible: triggerA, placement: 'right', template: 'bad-password-popover'],
                  [visible: triggerB, placement: 'right', template: 'throttled-popover']}"/>
-->
<input type="password"  
       data-bind="popover: { 
                  visible: triggerA, placement: 'bottom', template: 'A'}"/>

<script type="text/html" id="A">
    This is popover A
</script>

<br/>
<label>Trigger A<input type="checkbox" data-bind="checked: triggerA"></label>
<label>Trigger B<input type="checkbox" data-bind="checked: triggerB"></label>

JavaScript

ko.bindingHandlers.popover = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var value = ko.unwrap(valueAccessor());
        $(element).popover({
            html: true,
            content: function () { 
                return $('#' + ko.unwrap(value.template)).html(); },
            placement: value.placement,
            trigger: "manual",
            container: 'body'
        });

    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        if (valueAccessor().visible()) {
            $(element).popover('show');
            var popover = $("body .popover").last().get(0);
            ko.cleanNode(popover);
            ko.applyBindings(bindingContext.$rawData, popover);

        } else
            $(element).popover('hide');
    }
};

var vm = {
    triggerA: ko.observable(),
    triggerB: ko.observable()
}

ko.applyBindings(vm);