tags:

views:

242

answers:

2

I have a relatively simple page that has a couple of LI entries that I want to be able to show on click. The idea is to simulate PowerPoints logic where groups of elements appear when you click on the page.

In the "click()" handler for the parent "div" element I have:

$(function() {
    var currentReveal;
    var currentGroup = 1;

    currentReveal = $("[class*=Revealed]").hide().length;
    $("div").click(function() {
    if (currentReveal != 0) {
        var revealedElements = $("[class*=Revealed]").filter("[revealgroup='" +
                                 currentGroup + "']");
        $(revealedElements).show("normal");
        currentGroup += 1;
        currentReveal -= revealedElements.length;
    }
});

The HTML that this is acting on is:

    <div class="Body">
    <ul>

    <li>Lorem Ipsus</li>
    <ul>
        <li class="RevealedList" revealgroup="1" >Lorem Ipsus:</li>
        <ul class="Revealed" revealgroup="1">
            <li>Lorem Ipsus.</li>
            <li>Lorem Ipsus.</li>
        </ul>
        <li class="RevealedList" revealgroup="1">Lorem Ipsus</li>
     </ul>
     </div>

Unfortunately when the show() command finishes executing, the "li" entry has a style of "display:block" and not a style of "display:list-item" (verified with firebug and IE). I know I can trivially work around this problem (by updating the code to fix the style after the "show()" method has completed), but I'd like to know what I'm doing wrong.

+2  A: 

When you do .hide(), your li elements get display:hide, so .show() sets them to display:block because the previous display property value has been lost. So you have two alternatives:

  • Remove Revealed-like classes from the li and put them in the ul or other container element that is able to get display set to block or
  • Instead of .show(), try using something like .css({display:'list-item'})

I'd probably go with the second one.

If you want to achieve a .show("normal")-like effect, you can do something like

// assume the following var
var yourstuff = $(/* the stuff you're hiding */);

// instead of just calling .hide(), store width and height first
yourstuff.each(function() {
  $(this).data('orig_w',$(this).width())
         .data('orig_h',$(this).height())
}).hide()

// then, instead of resetting 'display', animate the stuff
yourstuff.css({display:'list-item', overflow: 'hidden', width:0, height: 0;})
  .animate({width: yourstuff.data('orig_w'), height: yourstuff.data('orig_h')},
     "normal", //speed
     "linear", //easing
     function() { // in the end, reset 'overflow' to show the bullet
       yourstuff.css('overflow', 'none');
     })

I hope the above snippet to be enough to give you an idea of what to do.

Miguel Ventura
IIRC, this is a known bug and should be fixed in one of the next versions of jQuery.
keithjgrant
Miguel: I'd like to get the animation effect that I get with .show("normal") though :(. I'll see if I can put the Revealed stuff on the ul though.
Larry Osterman
edited answer to provide way to better emulate .show() with the animation thingy
Miguel Ventura
Thanks Miguel, that helps a lot.
Larry Osterman
+1  A: 

@Larry & @Miguel:

I've just tested this with a simple script that hide()s and show()s my <li>s, and they were set back to "list-item". Actually, if you look at jQuery's source code, on the show() method, you will see:

jQuery.fn.extend({
show: function(speed,callback){
/* ... */
var old = jQuery.data(this[i], "olddisplay");
/* ... */
jQuery.data(this[i], "olddisplay", display);

And if you look at the hide() method, you will that it actually saves the value o display before setting it to none:

var old = jQuery.data(this[i], "olddisplay");
if ( !old && old !== "none" )
    jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));

The code I used to test it with Firebug:

<script type="text/javascript">
 $(function() {
  $("li").click(function() {
  $("li").hide();
  $("li").show();})
 });
</script>

<body>
 <ul>
  <li>foo</li>
  <li>foo</li>
 </ul>
</body>

Are you sure you can confirm the problem you are talking about? Maybe there's something important I didn't get, or that you didn't tell us.

Good luck!

Bruno Reis
The display is being set to "block" in show - the code "if ( display === "none" ) display = "block"; is executing. I believe that the code at this location should be the code you described above (jQuery.data(this...).
Larry Osterman
You could try setting some breakpoints on jQuery to see exactly what is going on. Try that! It is rather interesting.
Bruno Reis
@Larry: actually that line you highlighted is unimportant. The display style of the `li` elements in the code I've shown you is set about 10 lines before what you hightlighted: `var old = jQuery.data(this[i], "olddisplay"); this[i].style.display = old || "";` After this, IF it couldn't reset the display to the `olddisplay` value, THEN it will set it to block, as the code you've highlighted. Not in the case of the code I've shown you...
Bruno Reis
Bruno: I've put breakpoints in the code you which resets the style back to the old value. It doesn't get executed. I don't know why it doesn't get executed but it doesn't. For your example, you might try issueing the call to hide() in the ready handler and then the show() in the click handler. You're also not using an animation on your call to show() - try it with "show(normal)" (with a timeout jQuery executes a totally different path).
Larry Osterman
Oh, I see. Well, at least your problem is solved and we know what caused it! God luck!
Bruno Reis