Event Chaining and targeting issue in Jquery

Hello.

I’m coding my own jquery “powerpoint” type slide presentation. I have a script that uses load() to bring in separate HTML files as the “slides” and it fades them in and out when you click the “next” or “previous” buttons.

To kick it up another notch, I’d like each element on the page to slide into place from the right (sliding left into final position). I’d like to slide every item in the parent div (#presentationContainer) with a class of “animElement” to use the “margin-left” css property to appear to slide into place as it fades.

So, each element with that class would animate one after another until each one is faded in and in correct position.

This is one hell of an example of event chaining and is a bit above my meddle. I just need help with the sliding part in the animation. The fades all work fine.

My question is, how will I handle the sliding and where in the even chain will I put that code? How do you target an item and intercept it when it isn’t on the page yet?

Here is the script for the .nextButton:

$(‘.nextButton’).click(function(){
if($currentSlide < $numberOfSlides) {
$currentSlide += 1;
$(‘#presentationContainer’).load(‘slide-’ + $currentSlide + ‘.html’).hide().fadeIn(1000);
}
});

I might need to start another statement. Not sure if all of this can be chained into just one. Here’s the offset for the sliding elements.

animate({marginLeft: ‘+=40px;’})

If I try:
$(‘#presentationContainer’).load(‘slide-’ + $currentSlide + ‘.html’).hide().fadeIn(1000).animate({marginLeft: ‘+=40px;’});

The presentation Container is what gets animated. So I need a more refined targeting … Again, I’m trying to snag these elements before they get faded in and slide them into place.

Thanks
| scott

Hey Scott,

It might be beneficial for you to know that the .load() method also takes a callback. This callback will be executed once the file has been loaded, which ought to help you refine what you’re targeting as well.

e.g. a click handler method for the Next button:


function getSlide() {
    if($currentSlide >= $numberOfSlides) { 
        return;
    }

    $currentSlide += 1;

    $('#presentationContainer').load('slide-'+$currentSlide+'.html', function() {
        //find the parent and child and cache them
        var $parent = $(this), 
            $child = $parent.find(">section"); // whatever your container element *inside* your slide HTML files is

        $parent.fadeIn(1000); //fade in the parent
        $child.animate({left: '0%'}, 1000); at the same time begin sliding in your content
    }).hide();
}

$(document).ready(function(){
    $("#next").click(getSlide);
});

You might notice that I used the “left” property to animate and not the margin-left property as that also causes your content to be pushed around in an undesirable manner.

So make sure you also have some starting CSS like this:


#presentationContainer {
    width:1000px;
    margin:0 auto;
    overflow: hidden; /* This is the important bit */
}
section {
    position: relative;
    left:100%;
}

Awesome John. I see where you are going. For the most part it worked. I should mention that I also intended to have a previous button to reverse the order of the slides. I incorporated your code and added some of my own. The problem now is, for some reason, it’s ignoring the first line. The line where I tell it to automatically load slide1.html. And also the code I put in for the previous button isn’t working. Here’s my code in it’s entirety. Thanks again for your assistance John.

// begin document ready wrapper
$(document).ready(function(){

// loads first slide - not currently working
$(‘#presentationContainer’).load(‘slide-1.html’).fadeIn(1000);

var $numberOfSlides = 3;
var $currentSlide = 1;

function getSlideNext() {
if($currentSlide >= $numberOfSlides) {
return;
}

$currentSlide += 1;

$('#presentationContainer').load('slide-'+$currentSlide+'.html', function() {
    //find the parent and child and cache them
    var $parent = $(this), 
        $child = $parent.find("&gt;.slide"); // whatever your container element *inside* your slide HTML files is

    $parent.fadeIn(1000); //fade in the parent
    $child.animate({left: '0%'}, 1000);
}).hide();

}

$(‘.nextButton’).click(getSlideNext);

function getSlidePrevious() {
if($currentSlide <= $numberOfSlides) {
return;
}

$currentSlide -= 1;

$('#presentationContainer').load('slide-'+$currentSlide+'.html', function() {
    //find the parent and child and cache them
    var $parent = $(this), 
        $child = $parent.find("&gt;.slide"); // whatever your container element *inside* your slide HTML files is

    $parent.fadeIn(1000); //fade in the parent
    $child.animate({left: '0%'}, 1000);
}).hide();

}

$(‘.previousButton’).click(getSlidePrevious);

});// end document ready wrapper

From what I can gather your previous button is getting appended to the DOM via Ajax? If that’s correct then you need to delegate the click handler to the button class instead like below.

$(document).delegate('click', '.previousButton', getSlidePrevious);

However in jQuery 1.5 and above its recommended you use the on method as it does both event delegation and bubbling.

$(document).on('click', '.previousButton', getSlidePrevious);

No. The buttons are just in the markup. I have:

<div id=“controlPanel”><!-- open controlPanel –>
<input type=“submit” value=“Next” class=“nextButton”>
<input type=“submit” value=“Previous” class=“previousButton”>
</div><!-- close controlPanel –>

Just did something in the code that is causing it to not reverse.

I have the whole thing online if you want to see how it behaves.

http://savagepixels.com/quicksilver/testPres.html

Thanks.

It should actually be loading the slide fine, but if you’ve applied the CSS where the default state for it is to be offset to the left, then you’ll need to apply the same callback as you have in the prev/next callbacks.

i.e.


$('#presentationContainer').load('slide-1.html', function() {
    var $parent = $(this), 
    $child = $parent.find(">.slide"); 

    $parent.fadeIn(1000); //fade in the parent
    $child.animate({left: '0%'}, 1000);
})

Whoops just realised I didn’t answer this part either.

In your getSlidePrevious() function, the if-statement should compare to 0, not the number of slides :slight_smile:

i.e.


if($currentSlide <= 0) { 
    return;
}

Doh. Should have seen that coming with the previous slide thing.

Great advice. It’s working well now.

The last thing I though would be nice would be to have each element’s entry staggered a bit. So, within my .slide container div, I have various elements all with a class=“animElement”. I would like each one to do it’s CSS slide right after the one in front of it in the queue. When the “slide” loads the first element <h1> will slide … then each <p> tag will slide in, then the <img> … basically whatever I gave the class animElement to.

This is to simulate what you sometimes see in PowerPoint where the items do a similiar transition.

I’m learning a lot this way, so thanks. This stuff wasn’t in the book …

I actually built a presentation like that not long ago, but I cheated and used DeckJS :wink:

If you want to do that, I would recommend using CSS animations and some default classes to set up delays and durations.
For example:


.delay0-1 { -webkit-transition-duration: 0.1s; }
.delay0-2 { -webkit-transition-duration: 0.2s; }
.delay0-3 { -webkit-transition-duration: 0.3s; }

.duration0-1 { -webkit-transition-duration: 0.1s; }
.duration0-2 { -webkit-transition-duration: 0.2s; }
.duration0-3 { -webkit-transition-duration: 0.3s; }


NOTE: This code is from an app I’m building for iPad use, so I’m only using the -webkit- prefix. If you want to cater to more browsers you should of course consider putting all the prefixes in!
e.g.


.duration0-1 {
-webkit-transition-duration: 0.1s;
       -moz-transition-duration: 0.1s;
        -ms-transition-duration: 0.1s;
         -o-transition-duration: 0.1s;
            transition-duration: 0.1s;
}

Now all you need is some classes that perform the transitions, for example:


.slide-in {
    position:relative;
    -webkit-transition-property: left;
    -webkit-transition-timing-function: ease-out;
    left:100%;
}


.animate-in .slide-in {
    left:0%;
}

Note the .animate-in class? We need this to represent a different state than the initial one. There are various ways of accomplishing this, and I think this one might work for you. We just need to add an “addClass()” call to your callbacks.


//replace the $child.animate() call with this in each of your callbacks
$child.animate({left: '0%'}, 1000).addClass("animate-in");

You can then use a combination of these classes to animate your content


<div class="slide">
    <h1 class="slide-in duration0-3">Heading</h1>
    <p class="slide-in delay0-1 duration0-5">Para 1</p>
    <p class="slide-in delay0-5 duration0-5">Para 1</p>
    <p class="slide-in delay0-9 duration0-5">Para 1</p>
</div>

You can of course do all of these animations in JavaScript as well, and if you need to support more than just the latest browsers, then that’s something that isn’t too hard to do either :slight_smile:

You have a knack for concise explanations John. Well done. Thanks so much. Crystal Clear.

I should mention I just have it set up to use screen grabs as slides in this test version. Each slide will only be:

<!-- SLIDE 1 –>
<section class=“slide” id=“slide 1”>
<img src=“img/tempScreen_1.jpg” width=“908” height=“600”>
</section>

So, I got five of those that I was hoping to use to get everything up and functioning.

Hi John. Are you still out there? I was trying to use your recommendation of Deck.js to do my presentation since it’s already been set up and fussed over but for some reason I can’t get the buttons to function or even get it to do even simple sliding transitions. Do you foresee a problem with using images as buttons? I can’t see what the difference would be, but for some reason it won’t function.

Basically I’m having the type of trouble you have when you can’t get Jquery configured correctly, only I know it’s functioning. FOr instance, try to select the text in the footer that starts out with “By using this site …”. It’s as if that portion of my page is covered by something else. Weird.

Any idea what’s causing this funkiness? I actually had it working for one brief second. There was no sliding transition, but it did advance to the next slide. Now I can’t even get that.

http://savagepixels.com/quicksilver/

Thanks
| sc

You can disregard this last post. The problem appears to be the way I nested my “slides”. I should have had my <section> tags all directly under the <body> and I had them in another level which was throwing off the CSS.

Thanks anyway.