Bootstrap Tooltip with manual trigger and selector option
Asked Answered
C

1

17

I have a dynamic table, loaded with ajax. I want to show a tooltip when I hover the mouse over a row, but I want the tooltip to appear over a certain cell (with class .name) instead of above the entire row.

Also, using title function, I need to be able to get closest row id and return a custom template.

Here is my code:

<table class="table" id="myTable">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Country</th>
            <th>Statistics</th>
        </tr>
    </thead>
    <tbody>
        <tr id="1">
            <td >1</td>
            <td class="name">Name #1</td>
            <td>United States of America</td>
            <td>100%</td>
        </tr>
        <tr id="2">
            <td >2</td>
            <td class="name">Name #2</td>
            <td>United States of America</td>
            <td>50%</td>
        </tr>
    </tbody>
</table>

Initialization:

$('#myTable').tooltip({
    container: 'body',
    html: true,
    selector: 'td.name',
    trigger: 'manual',
    title: function() {
        // here will be custom template
        var id = $(this).parent().atrr('id');
        return id;
    }
});

Attempt One : Demo in jsFiddle

$('#myTable')
    .on('mouseenter focusin', 'tbody > tr', function() {
        $(this).find('td.name').tooltip('show');
    })
    .on('mouseleave focusout', 'tbody > tr', function() {
        $(this).find('td.name').tooltip('hide');
    });

Attempt Two : Demo in jsFiddle

var tip;
$('#myTable')
    .on('mouseenter focusin', 'tbody > tr', function() {
        tip = $(this).find('.offer-name');
        tip.tooltip(hereAllTooltipOptions);
        tip.tooltip('show');
    })
    .on('mouseleave focusout', 'tbody > tr', function() {
        tip.tooltip('hide');
    });

But I wonder greatly over the performance of such a solution. So, the question is how to do it and do it better?

Chloe answered 26/7, 2014 at 16:47 Comment(0)
T
37

The problem here is that you can't use the selector option when trigger is set to manual. The selector is used for delegation when bootstrap is handling the trigger events, but you've explicitly said that you'll be the one handling delegation, so it ignores the selector setting.

This means we gain nothing from pre-initializing with code like this:

$('.parent').tooltip({
    selector: '.child',
    trigger: 'manual'
})

It just says I want to set tooltips on .child elements, but don't do anything about it, because I'll be handling it later.

Which is fine, that's that what we wanted to do anyway when we used manual. We'll be the ones to dictate when the tooltip is shown or hidden.

Let's look at what a simple case of that would look like:

$('#myTable').on({
    'mouseenter': function() {
        $(this).find('td.name').tooltip('show');
    },
    'mouseleave': function() {
        $(this).find('td.name').tooltip('hide');
    }
},'tbody > tr');

Demo in js Fiddle

However, this won't work in this instance because we want to dynamically generate tooltips. When we call .tooltip('show') on a particular element, bootstrap looks at that element to see if it has been initialized or has a title. The above example works, because I've hard coded in a title, but how would we use this if we wanted to initialize this tooltip first?

Just Initialize on the fly, right before you show the tooltip, like this:

$('#myTable').on({
    'mouseenter': function() {
        $(this).find('td.name')
            .tooltip({
                container: 'body',
                html: true,
                trigger: 'manual',
                title: function() {
                    return this.parentNode.id;
                }
            }).tooltip('show');
    },
    'mouseleave': function() {
        $(this).find('td.name').tooltip('hide');
    }
},'tbody > tr');

So you don't incur the initialization cost on every hover, you can wrap the initialization in an if statement to check if it has already been initialized like this:

var $cell = $(this).find('td.name');
if (!$cell.data("bs.tooltip")) {
    $cell.tooltip({ /* options */ });
}
$cell.tooltip('show');

Demo in jsFiddle

Thompkins answered 26/7, 2014 at 17:24 Comment(5)
Thank you!! That is exactly what I needed :). Also, just found I can use $cell.data('bs.tooltip')for check if tooltip has been initialised.Chloe
Bootstrap documentation on 'selector' is quite vague. I completely overlooked the possibility that dynamic tooltips can simply be generated on the fly using tooltip() function and options itself. Thanks!Angelo
Thanks for this code, I was able to use it for popovers as well. Also as a heads up: I intend to use this code without attribution in my progress since it appears you are giving it freely.Austere
@Thompkins Thanks for the thoughtful reply. To me, it's just a hassle to attribute and keep up with them all. I actually usually keep a link back to the question in my source code, but that is usually it. And I may not do that if I understand the code myself. I asked about this one time (meta.#254118). Anyway, I do believe that you legally retain copyright and can allow others to use without attribution if you wish. For now, I will assume you do not wish to do that, which is completely acceptable.Austere
Thanks a lot @Thompkins . Ha, I think I can see you must have found it interesting because the number went up from 95 to 96 :) . Yes, please feel free to delete. take careAustere

© 2022 - 2024 — McMap. All rights reserved.