Search code examples
jqueryknockout.jstwitter-bootstrap-3modal-dialogpopover

Bootstrap modal popover with varying context dependent locations


Bootstrap modal popover looked like a good fit for my needs (modal functionality with a popover look): https://scruffles.github.io/BootstrapModalPopover/

I need to display the popover in different locations depending on where the user clicked, which I think is a common scenario (if you have 20 x 6 elements on a page, where the content is dynamic, you cannot even define 20 x 6 popover divs separately, it's not even possible).

The problem is that once the popover is displayed the first time, it sticks to that initial location. How can I overcome this? Here's a very simplified Fiddle: http://jsfiddle.net/csabatoth/NJZLh/5/

<div class="page">
    <div data-bind="foreach: items">
        <button class="btn" data-bind="text: txt, attr: { id: refid }, click: function(data,event) { $root.displayPopover(data) }" ></button>
    </div>
</div>

<div id="dialog" class="popover">
    <div class="arrow"></div>
    <h3 class="popover-title" id="popoverTitle"></h3>
    <div class="popover-content" id="popoverContent">
    </div>
    <div style="float: right; padding: 0px 15px 15px 15px">
        <button type="button" class="btn btn-default btn-sm" data-bind="click: function(data, event) { return $root.hidePopover(); }"><i class="icon icon-remove"></i></button>
    </div>
</div>

var ViewModel = function () {
    var self = this;

    function ItemObj(id, txt, msg) {
        var self2 = this;
        self2.id= id;
        self2.txt = txt;
        self2.msg = msg;
        self2.refid = "ref" + id;
    }

    self.items = ko.observableArray([
        new ItemObj(1, "First", "blabla1"),
        new ItemObj(2, "Second", "blabla2"),
        new ItemObj(3, "Third", "blabla3"),
        new ItemObj(4, "Fourth", "blabla4")
    ]);

    self.displayPopover = function(data) {
        $('#dialog').modalPopover({
            target: '#' + data.refid,
            placement: 'bottom'
        });
        $('#popoverTitle').html("Sample " + data.txt);
        $('#popoverContent').html("Sample editable content " + data.msg);
        $('#dialog').modalPopover('show');
    }

    self.hidePopover = function() {
        $('#dialog').modalPopover('hide');
    }
}

ko.applyBindings(new ViewModel());

You can see how I dynamically generate the ids (refid) for the elements where I can tie the popover to. The ids are generated well, and work for the first show. The problem maybe is in the modal popover plugin, in the $.fn.modalPopover? Once it's created the data, it never overrides it, so the second call won't modify anything:

https://github.com/scruffles/BootstrapModalPopover/blob/master/src/bootstrap-modal-popover.js#L118

if (!data) $this.data('modal-popover', (data = new ModalPopover(this, options)))

If the problem is in modal popover itself, I'm all right to modify that too.


Solution

  • Kyle Lee's fork solves the problem! http://jsfiddle.net/csabatoth/NJZLh/8/

    The fiddle's source is the same as before, the only difference that this time I include the fork's js instead of the original branch's js

    https://github.com/liyuankui/BootstrapModalPopover

    I discovered a cosmetic bug (if you'd have multiple direction popovers), see in my comments below.