Bind KO to a Bootstrap Popover

Show how to bind knockout to the contents of a Bootstrap popover

by Jason Butz

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.3.7/js/tether.min.js"></script>
<script src=" https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<div class="container" style="margin-top: 80px;">
    <!-- ko template: {afterRender: afterRender} -->
    <button class="btn btn-lg btn-primary" data-bind="attr:{ id: btnId}" data-toggle="popover" data-contentx="Hello World">
        Click Me
    </button>
    <!-- /ko -->
    <hr />
    <button class="btn btn-success btn-sm" data-bind="click: addItem">
        Add List Item
    </button>
</div>



<script id="demoPopoverTemplate" type="text/template">
    <div>
        <span>Hello World!</span>
        <div data-bind='foreach: myList'>
            <span class="tag tag-default" data-bind="text: $data"></span>
        </div>
    </div>
</script>

SCSS

@import url(https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.min.css);

JavaScript

class App {
    constructor() {
        this.btnId = Date.now();
        this.myList = ko.observableArray(['One', 'Two', 'Three', 'Four']);
    }
    addItem(viewModel) {
        viewModel.myList.push(Date.now());
    }
    afterRender(elements, viewModel) {
        // We need to have a single DOM element that contains everything we want in the popover
        //  A div with nothing on it should be fine
        // Here I am using jQuery to create the DOM elements for me
        //  from a string. It doesn't matter how they are created, they
        //  just must be DOM elements for KO to do the magic

        // Get the template element
        var templateEl = document.getElementById('demoPopoverTemplate');
        // Turn the template element's contents into a jquery object then extract the DOM
        //  elements
        var content = $(templateEl.innerText).get(0);
        // Set the content for a our popover
        $(`#${viewModel.btnId}`).popover({
            content: content,
            html: true
        });
        // Run KO on those DOM elements
        ko.applyBindingsToDescendants(viewModel, content);

    }
}


ko.applyBindings(new App());