3

It has come to my attention that the boostrap popover when hidden seems to destroy the content and redo it when you show it.

Please take a look a this example.

If you write on the input, hide the popover and show it again, the input will be empty.

Shouldn't it just not display it and then show it again, without using the content?

What's the best way to avoid that? Do I have to display: none the popover myself, or is there a bootstrap way?

Note that I'm not interested in storing and keeping the text of the input, that's not the point of this question, I want to keep the html as it is because of a jquery plugin that is loaded and activated inside.

Trufa
  • 39,971
  • 43
  • 126
  • 190

4 Answers4

3

I had a similar need. I am using popover to display an in place edit form field. Once the value was saved, if you clicked the popover again the same source HTML was copied and the old value was selected. I played with setting the value on update and a few other things and nothing worked or I was not happy with the result.

I came up with this solution where instead of letting the show/hide events trigger I manually show and hide the popover.

$(document).on('click', '.ajax-value', function() {
    // We only want to init the popover once
    if (typeof $(this).data('bs.popover') == "undefined") {
        // Init the popover and show immediately
        $(this).popover({
            'content': $(this).closest('.ajax-edit').find('.ajax-field').html(),
            'html': true,
            'title': $(this).attr('data-title'),
            'placement': 'auto'
        }).popover('show');

        // Hook into show event and return false so parent does not run
        $(this).on('show.bs.popover', function () {
            return false;
        });

        // Same for hide, don't let parent execute
        $(this).on('hide.bs.popover', function () {
            return false;
        });
    } else {
        // If we already created popover, just toggle hidden class
        $(this).closest('.ajax-edit').find('.popover').toggleClass('hidden');
    }
});

// This is a custom close button in the popover
$(document).on('click', '.ajax-field-close', function(){
    // Just add the hidden class
    $(this).closest('.ajax-edit').find('.popover').addClass('hidden');
});
dotcomly
  • 2,154
  • 23
  • 29
1

It is not possible to only 'hide' the popover using default bootstrap, event the .popover('hide') will destroy HTML popover (while .popover('destroy') destroy the popover property from the element).

I think the best way to deal with that is to save what you want to save when the popover is hidden and to replace it when the popover is shown. You can do that using the popover event: shown.bs.popover and hide.bs.popover.

// By default, your popover content is empty, and you got somewhere a <div id="mypopovercontent"></div> which is hidden

$('a').on('shown.bs.popover', function (e) {
    $(this).data('bs.popover').$tip.find('.popover-content')
         .html('')
         .append($('#mypopovercontent')) ;
    $('#mypopovercontent').show();
}) ;

$('a').on('hide.bs.popover', function (e) {
    $('body').append($('#mypopovercontent')) ;
    $('#mypopovercontent').hide();
}) ;

I didn't check the code above, but you get the idea!

Holt
  • 36,600
  • 7
  • 92
  • 139
  • Thanks, but I'be just updated the question because I was not clear the first time, I don't actually want to keep the text, rather the html, since this is not actually my problem, rather a problem with a jquery plugin loaded inside the popover. I do get your point though, thanks and sorry for the misunderstanding. – Trufa Apr 30 '14 at 15:09
  • @Trufa Okay, so it will be really more complicated because you have to manually hide / show the popover (without using `.popover('hide')` as explained in my answer, but you also have (because you're not using the popover function) to deal with the popover position... – Holt Apr 30 '14 at 15:17
  • @Trufa Maybe you can use a trick: When the popover is hidden, you move the content from the popover to elsewhere (without cloning), so the element stay the same (something like `$('body').append(content);`), then you hide it, and when the popover is shown, you do the reverse thing. – Holt Apr 30 '14 at 15:18
  • @Trufa I've edited my answer, tell me if it's get closed to what you want! – Holt Apr 30 '14 at 15:21
  • Thanks for the input, I'm trying an unrelated approach now, but if it doesn't work, I'll give this a try... – Trufa Apr 30 '14 at 15:21
  • @Trufa I tested the updated code, it worked for me with simple HTML. It should work with some complicated code because the HTML content is not copied but only moved. Some plugin won't work anyway because they don't support moving element. – Holt Apr 30 '14 at 15:26
1

Why not clone the HTML and use that as your content?

<a href="#" rel="popover" data-popover-content="#myPopover">My Popover</a>

$('[rel="popover"]').popover({
    container: 'body',
    html: true,
    content: function () {
        var clone = $($(this).data('popover-content')).clone(true).removeClass('hide');
        return clone;
    }
})
sevmusic
  • 126
  • 6
0

I stumbled on this question and ended up making my own solution so that I could use a color picker. It is similar to Holt's answer except it actually shifts the HTML in question between two different parent divs, one of which is hidden. This way, any changes the user made are preserved.

With this code you would have the HTML starting within #color-picker-popover-parentwhich is a hidden div. I have only tried it in Bootstrap v3.

$('.color-button').popover({
        html: true,
        content: '<div id="color-picker-popover-temp-parent"></div>',
        title: '',
        placement: 'bottom'
    }).on('hide.bs.popover',function(){
        $('#color-picker-popover').detach().appendTo('#color-picker-popover-parent');
    }).on('inserted.bs.popover',function(){
        if($('#color-picker-popover-temp-parent').length)
        {
            $('#color-picker-popover').detach().appendTo('#color-picker-popover-temp-parent');
        }

    });
user1442605
  • 192
  • 1
  • 8