Jump to content
Larry Ullman's Book Forums

Page 385 - Chapter 10 - Tooltips


Recommended Posts

Attempted to generate a tooltip from code listed on pages 384 and 385.

 

HTML was looking like this:

 

<div>
<label for="username">Username<span class="tooltip">Some snappy tooltip here</span></label>
<input type="text" name="username" id="username"/>
</div>

 

Tested page. No tooltip.

 

Instead, the console.log shows:

 

TypeError: target.previousSibling.lastChild is null
"target.previousSibling.lastChild.style.visibility = 'visible';"

 

Tested the download files. Tooltip works.

 

My code is exactly like the download files, and won't make a tooltip.

 

So, after ((timeSpent >= 1 hour) && (currentHair < previousHair)), I remove the hard return after </label> on a whim . . . and Viola! - tooltip appears!

 

Now the HTML code looks like this:

 

<div>
<label for="username">Username<span class="tooltip">Tooltip</span></label><input type="text" name="username" id="username"/>
</div>

 

Apparently adding hard returns (formating page for easier reading) introduces a new DOM node that prevents 'previousSibling' in the javascript function from reaching all the way back to <label>.

 

So then, no hard returns if you expect to go tripping through the DOM.

 

Hope this helps save some hair.

 

~ David

 

Win 7 Home Premium

Firefox 17.0

Link to comment
Share on other sites

Yes, different browsers have different ways of handling child nodes, and in some browsers, a single white space between tags will create a new text node (i.e., child node).

 

That's why I always explicitly check for what I'm looking for by using if statements, etc.

In your case, perhaps just using document.getElementsByTagName on the span elements would work best.

 

Also, your if statement about time spent and hair loss cracked me up. Very amusing. Thanks.

  • Upvote 1
Link to comment
Share on other sites

  • 3 weeks later...

Thanks... I just had the exact same problem (using firefox.) David's solution worked for me, but I am now looking at different ways to refer to the span element as the DOM traversal method seems too risky.

 

Simon

 

I've settled on this for now:

target.parentNode.getElementsByTagName('span')[0].style.visibility = 'visible';

Link to comment
Share on other sites

simon, your method does work, but it's pretty darn inefficient.

 

You might be better off assigning a particular class to all the span element tooltips, and then writing a custom getElementsByClassName function/method to handle grabbing them all. (Note: There are several good getElementsByClassName implementations on the Internet, and modern browsers have a built-in getElementsByClassName method, which is much more efficient than anything we could possibly write.)

Link to comment
Share on other sites

Thanks for looking at that HartleySan. I'm trying to stay away from libraries for the moment. I did see today that there is an API for traversing documents as trees of elements while ignoring text nodes. It's not implemented in IE though. Here's what I've been playing around with. It seems to work, but doesn't test for nextElementSibling or previousElementSibling:

/*jslint browser: true*/ /*global U*/
/**
* Return the nth sibling element of Element e.
* If n is positive, return the nth next sibling element.
* If n is negative, return the nth previous sibling element.
* If n is 0, return e.
*
**/

function sibling(e, n) {
'use strict';
while (e && n !== 0) {
if (n > 0) { // Find the next element sibling.
// If e is not a text node (nodeType !== 1)
// find the next sibling and decrement n by 1.
if (e && e.nodeType !== 1) {
e = e.nextSibling;
n = n - 1;
} else { // If e exists it's a text node.
// Try the next sibling. Do not decrement.
e = e.nextSibling;
}
} else { // Find the previous element sibling.
if (e && e.nodeType !== 1) {
e = e.previousSibling;
n = n + 1;
} else {
e = e.previousSibling;
}
}
}
return e;
}

- based on Javascript - The Definitive Guide (pages 372 - 374)

Link to comment
Share on other sites

Your solution seems okay, so use it if it works.

 

For the record though, I was not recommending the use of a library.

Some browsers have a built-in getElementsByClassName method that is really fast (because it's built-in). You could easily write a single if statement to feature test for the method, and if it's not supported, use whatever method works best for you.

None of that involves using a library, and for browsers that have the built-in method, you'll get a huge performance boost.

Link to comment
Share on other sites

 Share

×
×
  • Create New...