Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bootstrap popover with knockout.js

I've got an application receiving some data through AJAX-call. After that, received data binds to DOM-elements using knockout.js library. I'd like to use boostrap's unobtrusive markup for creating popovers like this:

<table class="table table-condensed" data-bind="foreach: items">
    <tr>
        <td><b data-bind="text: $data.id"></b></td>
        <td data-bind="text: $data.title"></td>
        <td><a href="#" rel="popover" data-bind="attr: {title: $data.info}" data-placement="top">Info</a></td>
    </tr>
</table>

According to the latest bootstrap documentation, implicit call of something like $('.popover').popover() isn't required, however, it's not working.

I suppose, that boostrap.js perform some DOM-analysis on document.ready and perform all needed work for popover to work. And the question: is there some way to tell bootstrap.js to perform similar job for data after receiving AJAX response? Or how this kind of requirements can be achieved?

like image 683
koss Avatar asked Aug 27 '12 10:08

koss


2 Answers

You can create custom dataBinding to make that element popover. Check this jsfiddle demo

ko.bindingHandlers.bootstrapPopover = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var options = ko.utils.unwrapObservable(valueAccessor());
        var defaultOptions = {};        
        options = $.extend(true, {}, defaultOptions, options);
        $(element).popover(options);
    }
};

var viewModel = {

    items: ko.observableArray([{
        "id": 1,
        "title": "title-1",
        "info": "info-1"},
    {
        "id": 2,
        "title": "title-2",
        "info": "info-2"},
    {
        "id": 3,
        "title": "title-3",
        "info": "info-3"}])

}

ko.applyBindings(viewModel);​

And html

<div class="container">
    <div class="hero-unit">     
        <table class="table table-condensed" data-bind="foreach: items">
            <tr>
                <td><b data-bind="text: $data.id"></b></td>
                <td data-bind="text: $data.title"></td>
                <td><a href="#" data-bind="bootstrapPopover : {content : $data.info  }">Info</a></td>
            </tr>
        </table>
    </div>
</div>​
like image 157
Luffy Avatar answered Nov 12 '22 07:11

Luffy


"According to the latest bootstrap documentation, implicit call of something like $('.popover').popover() isn't required, however, it's not working."

I can't find anywhere in the docs that states that. In fact, they state quite the opposite. Namely, Twitter Bootstrap does not automatically initialize popovers or tooltips on a page. From the docs:

For performance reasons, the Tooltip and Popover data-apis are opt in. If you would like to use them just specify a selector option.

In order to "opt in", as they say, you would attach the Popover object to an element which contains all the popovers which might appear on the page. Here's one way of doing it:

$('body').popover({selector: '[rel="popover"]'});

I believe the performance considerations originally in mind came from the fact that prior to 2.1, the Popover plugin was by default triggered by mouseenter and mouseleave events, which are certainly not something you want to be constantly processing for an entire page.

Since 2.1, the default is now click, which shouldn't pose any performances issues. Nevertheless, if you can determine an element farther down the DOM than body to which to attach the Popover object, that is always preferred. However, depending on where you are displaying the AJAX content, body might be your best bet.

like image 39
merv Avatar answered Nov 12 '22 06:11

merv