tags:

views:

38

answers:

2

My below toggle() breaks when I uncomment the line $('.comments').slideUp('slow'); in the effects chain on the first half of the toggle.

When I copy this code and the associated CSS and HTML into their own page everything works fine, as to identical pieces of code on the same page that toggle other elements.

I get no errors or anything in firebug, does anyone have any idea why the slideUp() would cause the second half of the toggle() to break?

$('#show_hide_comments').toggle(function()
    {
        //alert('1');
        $('#show_hide_comments').attr('src','images/up.png');

        $('.comments').fadeTo('slow', 0.01, function()
        {
            //$('.comments').slideUp('slow');
        });

    },function()
    {
        $('#show_hide_comments').attr('src','images/down.png');

        $('.comments').slideDown('slow', function()
        {
            $('.comments').fadeTo('slow', 1);
        });
    });

Full code below:

<?

    //include_once '../cookie_factory.php';
    include_once '../connect.php';
?>

<style>


    .comments_container
    {
        position:relative;
        top:240px;
        left:15px;
    }

    .show_hide_comments
    {
        padding-left:10px;
    }
    .comments
    {

        position:relative;
        width:900px;
        background-color:#CCC;
        padding-bottom:10px;

        border-radius:5px;
        -moz-border-radius:5px;
        -webkit-border-radius:5px;

    }


    .new_comment
    {
        position:relative;
        padding-bottom:30px;
        padding-left:10px;
        display:inline;
    }


    .new_comment input 
    {
        font-family:Tahoma;
        font-size:12px;
        width:585px;
        height:25px;
        border-style: solid, 2px;
        border-color:#000;
    }
    .author
    {
        padding-top:15px;
        padding-left:10px;
        display:inline;
    }
    .author input
    {
        font-family:Tahoma;
        font-size:12px;
        width:80px;
        height:25px;
        border-style: solid, 2px;
        border-color:#000;

    }
    .email
    {
        padding-top:15px;
        padding-left:10px;
        display:inline; 
    }
    .email input
    {
        font-family:Tahoma;
        font-size:12px;
        width:155px;
        height:25px;
        border-style: solid, 2px;
        border-color:#000;  
    }
    .comment_check
    {
        position:relative;
        display:inline;
        padding-left:5px;
        top:2px;
    }

    .captcha
    {
        position:relative;
        top:5px;
        display:none;
        padding-left:10px;      
    }

    .captcha_statment
    {

        display:inline;
        font-family:Tahoma;
        font-size:14px;
    }
    .captcha_response
    {
        display:inline;
        padding-left:5px;
    }
    .captcha_response input
    {
        font-family:Tahoma;
        font-size:14px;
        width:50px;;
        height:25px;
        border-style: solid, 2px;
        border-color:#000;
    }
    .captcha_check
    {
        position:relative;
        display:inline;
        padding-left:5px;
        top:2px;

    }
    .captcha_result
    {
        display:inline;
        font-family:Tahoma;
        font-size:14px;
        padding-left:5px;
    }
    .the_comments
    {
        padding-top:10px;
        padding-left:10px;
        font-family:Tahoma;
        font-size:12px;
    }
    .full_comments_toggle
    {
        padding-top:10px;
        font-family:Tahoma;
        font-size:12px;
    }
    .full_comments
    {
        padding-top:10px;
        display:none;
    }

</style>

<script src="jquery-1.4.2.min.js"></script>

<script>

$(document).ready(function()
{
$('#comment').keyup(function()
        {

            // get new length of characters
            var length = $(this).val().length;
            var content = $(this).val();               

            //if the comment field has at least 1 character AND is not the original value then enable the submit button
            if ( length >= 1 && content != "your comment here...")
            {

                $('#comment_check').removeAttr('disabled');
                $('#comment_check').attr('src','images/check.png');


            }
            else if ( length == 0 || content == "your comment here...")
            {
                $('#comment_check').attr('disabled', 'disabled');
                $('#comment_check').attr('src','images/uncheck.png');
            }
        });

        $('#comment_check').click(function()
        {
            //alert('show captcha');
            $('.captcha').css( 'display', 'inline' );
        });

        //get the captcha value and check to see if it is correct. if it is, submit
        $('#captcha_check').click(function()
        {   

            $('#captcha_check').attr('disabled','disabled');
            $('#captcha_check').attr('src','images/uncheck.png');

            var captcha = $('#captcha_response').val();
            var comment = $('#comment').val();
            var name = $('#name').val();
            var email = $('#email').val();

            //rating = rating.substr(5);

            $.ajax({
                type: "GET",
                url: "ajax/check_captcha.php",
                data: ({ captcha:captcha , comment:comment , name:name , email:email }),
                dataType: "json",
                success: function(data)
                {

                    //alert( data );

                    if( data == 'success')
                    {
                        $('.captcha_result').css('color','black');
                        $('.captcha_result').html('Comment submitted for aproval.');
                    }
                    if( data == 'fail')
                    {

                        $('#captcha_check').removeAttr('disabled');
                        $('#captcha_check').attr('src','images/check.png');

                        $('.captcha_result').css('color','red');
                        $('.captcha_result').html('Uh no...');
                    }

                    //on success set... the average rating.. and yelllow stars
                    //var count = 0;
                }
                ///$(".average").html( "Average rating of " + data[0] + " votes: " + data[1] );
            });
        });

        //$("input, textarea").focus(function()
        //{
            // only select if the text has not changed
        //  if(this.value == this.defaultValue)
        //  {
        //      this.select();
        //  }
        //});

        $("input, textarea").click(function()
        {
            // only select if the text has not changed
            if(this.value == this.defaultValue)
            {
                this.select();
            }
        });


        //toggle to show/hide comments

        $('#show_hide_comments').toggle(function()
        {
            $('#show_hide_comments').attr('src','images/up.png');

            $('.comments').fadeTo('slow', 0.01, function()
            {
                $(this).slideUp('slow',function()
                {
                });
            });
        }, function()
        {
            $('#show_hide_comments').attr('src','images/down.png');

            //alert('wtf');

            $('.comments').slideDown('slow', function()
            {
                $(this).fadeTo('slow', 1, function()
                {
                });
            });
        });


        //toggle to show full comments
        $('#full_comments_toggle').toggle(function() 
        {

            $('#full_comments_toggle').attr('src','images/down.png');

            $('.full_comments').slideDown('slow', function()
            {
                $(this).fadeTo("slow", 1, function()
                {
                });
            });

        }, function() 
        {

            $('#full_comments_toggle').attr('src','images/up.png');

            $('.full_comments').fadeTo('slow',0.01, function() 
            {
                $(this).slideUp("slow", function()
                {
                });
            });
        });
});
</script>



<div class="comments_container">

<div class="show_hide_comments"><img id="show_hide_comments" src="images/down.png" width="19" height="10" alt="Expand" />

    <div class="comments">
        <div class="new_comment_container">
            <div class="new_comment"><input id="comment" name="comment" type="text" value="your comment here..."></div>
            <div class="author"><input id="name" name="name" type="text" value="your name"></div>
            <div class="email"><input id="email" "name="email" type="text" value="your email"></div>

            <div class="comment_check"><input id="comment_check" type="image" src="images/uncheck.png" HEIGHT="16" WIDTH="16" BORDER="0" ALT="Submit Comment!" DISABLED></div>
        </div>   

        <div class="captcha">
            <div class="captcha_statment">Mostly Dirty, Always:</div><div class="captcha_response"><input id="captcha_response" name="captcha_response" type="text" value="" size="5" maxlength="5"></div>
            <div class="captcha_check"><input id="captcha_check" type="image" src="images/check.png" HEIGHT="16" WIDTH="16" BORDER="0" ALT="Submit Captcha!"></div>
            <div class="captcha_result"></div>
        </div>

        <div class="the_comments">
            <?php

                $query = mysql_query("SELECT * FROM comments WHERE approved = 1 LIMIT 3");  

                while($comments = mysql_fetch_array($query))
                {
                    $date = date( 'F jS', strtotime($comments['date']));

                    echo '<div class="comment" id="'.$comments[id].'">'.$date.' - '.$comments[comment].' - '.$comments[name].'</div>';
                }
            ?>

            <div class="full_comments_toggle"><img id="full_comments_toggle" src="images/up.png" width="19" height="10" alt="Expand" />
            <?  
                $query = mysql_query("SELECT * FROM comments WHERE approved = 1 LIMIT 3,10000");    
                $count = mysql_num_rows($query);

                echo 'Show '. $count . ' more comments.';
            ?>

            </div>

            <div class="full_comments">
            <?php

                while($comments = mysql_fetch_array($query))
                {
                    $date = date( 'F jS', strtotime($comments['date']));

                    echo '<div class="comment" id="'.$comments[id].'">'.$date.' - '.$comments[comment].' - '.$comments[name].'</div>';
                }
            ?>
            </div>
        </div>
    </div>


</div>
</div>
+2  A: 

You should use this instead of a selector in the callback, like this:

$('#show_hide_comments').toggle(function() {
    //alert('1');
    $('#show_hide_comments').attr('src','images/up.png');

    $('.comments').fadeTo('slow', 0.01, function()
    {
        $(this).slideUp('slow');
    });

},function()
{
    $('#show_hide_comments').attr('src','images/down.png');

    $('.comments').slideDown('slow', function()
    {
        $(this).fadeTo('slow', 1);
    });
});

If you don't do it like this (use a selector), and you have say 10 .comments elements, bad things can happen with the animation queue. You have to remember the callback fires for each animated element, so if 10 .comments fade out, they'll each queue a .slideUp() on each .comments element again, suddently causing 100 animations, not 10.

By using $(this) you're calling .slideUp() for the element that just finished fading out, not any others.


Actually, on second thought, there are animations, they can just be queued, like this:

$('#show_hide_comments').toggle(function() {
  $(this).attr('src','images/up.png');
  $('.comments').fadeTo('slow', 0.01).slideUp('slow');
}, function() {
  $(this).attr('src','images/down.png');
  $('.comments').slideDown('slow').fadeTo('slow', 1);
});

Are you getting the same result if you're adding to the queue immediately like this?


One more note, there's some invalid HTML going on here:

<input id="email" "name="email" type="text" value="your email">

You should remove that extra " before name="email" to avoid other issues :)

Nick Craver
While true that's almost certainly irrelevant here.
cletus
He should also use it for the `#show_hide_comments` in `.toggle()`. I don't see how that would change the outcome, though.
patrick dw
@cletus - It is...I added reasoning onto how this happens, and quickly causes problems in IE for example, with low thresholds for scripts.
Nick Craver
@Nick yea I had it as `this` before and there is only one div with a class of .comments
ian
@patrick - I tried to address this as clearly as possible, basically you're causing n^2 animation queues, if you have more than a few elements this can get expensive *real* fast (IE blows up pretty early).
Nick Craver
@ian - In that case...what "breaks"? Does the `fadeTo` not happen, does it stop and not slide up?
Nick Craver
Nick - Your update is indeed clear. I left the comment before I saw that.
patrick dw
The entire second half of the `toggle()` fails. The `#show_hide_comments` wont change images, and the second chain that shows the `.comments <div>` again will not happen. Basically only the first half will happen, but if I comment out the `slideUp` then the `toggle` works normally.
ian
@ian - If you have only one `.comments` I'm not seeing a problem with only the code you posted...can you post the markup that goes with it?
Nick Craver
@Nick, ok I added it on but the thing is when I do this code. Separately from the rest of the page it runs fine, that's why I a trying to identify possible conflicts because the whole thing is too large to look at really.
ian
@ian - Is it behaving the same way in every browser?
Nick Craver
In the latest FF and Safari on OS X and Chrome on Windows yes... I did notice though if I keep clicking the toggle before one of the toggles completes it keeps going back and forth but once I let it fully toggle it is dead.
ian
@ian - Just curious here, take a look at: `<div class="email"><input id="email" "name="email" type="text" value="your email"></div>`, rey removing that extra quote before `name=` on there. I'm still trying to narrow down a cause here for your main issue, but that can lead to other issues.
Nick Craver
So I took out that extra quote and the page works! Then I put it back in and it still works correctly... Don't know if that was the fix or what but you can put it in as answer and ill give it to yah for sure!
ian
@ian - Added...hopefully the other addition simplifies your code a bit as well :)
Nick Craver
A: 

For me this works perfectly in Firefox 3.6, Chrome 5 and IE 8 (with and without DOCTYPE, which I'd suggest you also add for many reasons). I took your code and made it static HTML for testing purposes.

If you click it repeatedly in quick succession it will break however but that's because you're not handling the animation queue correctly. It's a good practice to stop() animations. You don't even have to do it repeatedly. If you click it twice really fast you may break it as well.

Also, inside event handlers you generally want to use this to refer to the source of the event (if not the source from the event object) rather than re-selecting, which could have unforeseen (and typically undesired) consequences.

Lastly, animations can be queued directly without using a callback.

Try:

$('#show_hide_comments').toggle(function() {
  $(this).attr('src','images/up.png');
  $('div.comments').stop().fadeTo('slow', 0.01).slideUp('slow');
}, function() {
  $(this).attr('src','images/down.png');
  $('div.comments').stop().slideDown('slow').fadeTo('slow', 1);
});

and tell me what happens.

cletus
Is this queuing of effects better than chaining?
ian