Reputation: 17487
I'm trying to create a custom tooltip by attaching hover event handlers to elements with a title
attribute.
The code works on elements at page load, but when I try to incorporate dynamic elements, the tooltip is not disappearing when my mouse leaves the target element.
Show Tooltip
Urb.showTooltip = function() {
var $element = $(this);
var $tooltip = $element.data('tooltip');
var $tip = $element.attr('title');
console.log('show');
if(!$tooltip) {
// create a tooltip element
$tooltip = $('<div />');
$tooltip.addClass('tooltip');
$tooltip.text($tip);
Urb.$body.append($tooltip);
// position the tooltip
Urb.positionTooltip($tooltip, $element);
$element.data('tooltip', $tooltip);
// activate custom tooltip and deactivate browser tooltip
$tooltip.addClass('active');
$element.attr('tooltip', $tip);
$element.removeAttr('title');
} else {
// position and activate custom tooltip
Urb.positionTooltip($tooltip, $element);
$tooltip.addClass('active');
}
};
Hide Tooltip
Urb.hideTooltip = function() {
var $element = $(this);
var $tooltip = $element.data('tooltip');
console.log('hide');
if($tooltip){
$tooltip.removeClass('active');
}
};
Note: Urb
is just a global object I've created as a namespace for my project.
So, nothing crazy going on there. I originally attached the tooltip logic to jQuery's .hover()
function:
$('[title]').hover( Urb.showTooltip, Urb.hideTooltip );
That worked just fine, but now, when I try to attach the events to dynamic elements, the Urb.hideTooltip
is not getting called at all, as it doesn't even log "hide" to my console.
Urb.$body.on('mouseover', '[title]', Urb.showTooltip);
Urb.$body.on('mouseleave', '[title]', Urb.hideTooltip);
Note: Urb.$body
is reference to $('body')
Why doesn't the hideTooltip
function get called? What am I missing?
Upvotes: 1
Views: 111
Reputation: 2988
Solution 1
Use CSS-only :hover
tooltips using :after
pseudo-elements with content: attr( title ) )
.
See: W3schools
Warning: this is not for all browsers out there, like IE, who gets left behind everytime... ;)
Solution 2
I've rewritten your code somewhat, to avoid referencing errors, etc. The only thing missing is the positioning function.
EDIT: Now it doesn't use a single tooltip <div>
, but sets up tooltip <div>
's for each item on first hover, by removing the title
and after using it to create the tooltip <div>
.
Have a look:
var Urb = {};
Urb.showTooltip = function() {
// Get current element
var $element = $(this);
// Get tooltip data (if it's there)
var tooltipText = $element.data('tooltip');
// Get title for backup
var tip = $element.attr('title');
console.log('show');
// If title is still set, set it to tooltip data and remove title attribute
if( typeof tip !== undefined && tip !== false) {
// Remove title attribute
$element.removeAttr('title');
// Create new tooltip div
var $newTip = $('<div />').addClass('tooltip').text( tip );
// Append it to the element
$element.append( $newTip );
}
$element.find('div.tooltip').addClass('active');
};
Urb.hideTooltip = function() {
console.log('hide');
// Empty tooltip div and deactivate it
$(this).find('div.tooltip').removeClass('active');
};
var last_item_nr = 3;
function addItem() {
var next_nr = ++last_item_nr;
$elm = $('<div></div>');
$elm
.html('Item ' + next_nr + '<div class="tooltip">Tooltip for item ' + next_nr + '</div>' )
.hover( Urb.showTooltip, Urb.hideTooltip );
$('#items').append( $elm );
console.log( 'Added item ' + next_nr );
}
$( document ).ready(function() {
Urb.$body = $('body');
$('#items > div').hover( Urb.showTooltip, Urb.hideTooltip );
});
#items > div {
position: relative;
float: left;
clear: left;
width: 200px;
border: 1px solid #eee;
}
#items > div > .tooltip {
position: absolute;
top: 0px;
left: 100%;
background-color: #ccc;
opacity: 0;
}
#items > div > .tooltip.active {
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="addItem();">Add item</button>
<div id="items">
<div title="Tooltip for item 1">Item 1</div>
<div title="Tooltip for item 2">Item 2</div>
<div title="Tooltip for item 3">Item 3</div>
</div>
Upvotes: 2
Reputation: 17487
OMG, I can't believe I didn't think of this!!!
In my showTooltip
function, I am removing the title
attribute!
What an idiot!!
$element.removeAttr('title');
So, when the tooltip showed, the dynamic element check stopped working. I commented out that line of code and it works.
Now, I just have to figure out how to prevent the browser tooltip from showing.
Update:
Turns out I did need to remove the title
attribute in order to disable browser tooltips. So, I made a few changes to my dynamic selector.
// showTooltip
$element.attr('data-title', $tip);
$element.removeAttr('title');
// window.load
Urb.$body.on('mouseover', '[title], [data-title]', Urb.showTooltip);
Urb.$body.on('mouseleave', '[title], [data-title]', Urb.hideTooltip);
Upvotes: 1