Create a Simple Slideshow Using MooTools, Part II: Controls and Events

By  on  

Christina Ricci

Last week we created a very simple MooTools slideshow script. The script was very primitive: no events and no next/previous controls -- just cross-fading between images. This tutorial will take the previous slideshow script a step further by:

  • Adding "Next" and "Previous" controls.
  • Adding a "Table of Contents" so the user may click to any image.
  • Pausing the slideshow when the user places their mouse in the container; resuming the slideshow when the use mouses out.

Obviously our MooTools JavaScript code is going to change quite a bit so be prepared to (mostly) restructure the previous post's JavaScript code.

The HTML

<div id="slideshow-container">
	<img src="slideshow/cricci1.jpg" alt="Christina Ricci" />
	<img src="slideshow/cricci2.jpg" alt="Christina Ricci" />
	<img src="slideshow/cricci3.jpg" alt="Christina Ricci" />
	<img src="slideshow/cricci4.jpg" alt="Christina Ricci" />
	<img src="slideshow/cricci5.jpg" alt="Christina Ricci" />
</div>

Nothing has changed from the previous post. Just images of Christina Ricci which will set your heart ablaze.

The CSS

#slideshow-container	{ width:512px; height:384px; position:relative; }
#slideshow-container img { width:512px; height:384px; display:block; position:absolute; top:0; left:0; z-index:1; }
.toc					{ position:absolute; left:0; bottom:20px; z-index:2; display:block; width:20px; background:#6D84B4; color:#fff; text-align:center; padding:3px; text-decoration:none; }
.toc-active				{ background:#fff; color:#6D84B4; }
#next					{ position:absolute; bottom:20px; right:20px; z-index:2; display:block; width:20px; background:#6D84B4; color:#fff; text-align:center; padding:3px; text-decoration:none; }
#previous				{ position:absolute; bottom:20px; right:60px; z-index:2; display:block; width:20px; background:#6D84B4; color:#fff; text-align:center; padding:3px; text-decoration:none; }

We've added the toc and toc-active CSS classes. The toc-classed items will be absolutely position at the bottom of the container. We'll calculate the left value of each item with MooTools as we don't want them to overlap. We've also defined CSS rules for the Next and Previous buttons we will generate. Feel free to style the TOC items and buttons any way you'd like.

The MooTools JavaScript

window.addEvent('domready',function() {
	/* settings */
	var showDuration = 3000;
	var container = $('slideshow-container');
	var images = container.getElements('img');
	var currentIndex = 0;
	var interval;
	var toc = [];
	var tocWidth = 20;
	var tocActive = 'toc-active';
	
	/* new: starts the show */
	var start = function() { interval = show.periodical(showDuration); };
	var stop = function() { $clear(interval); };
	/* worker */
	var show = function(to) {
		images[currentIndex].fade('out');
		toc[currentIndex].removeClass(tocActive);
		images[currentIndex = ($defined(to) ? to : (currentIndex < images.length - 1 ? currentIndex+1 : 0))].fade('in');
		toc[currentIndex].addClass(tocActive);
	};
	
	/* new: control: table of contents */
	images.each(function(img,i){
		toc.push(new Element('a',{
			text: i+1,
			href: '#',
			'class': 'toc' + (i == 0 ? ' ' + tocActive : ''),
			events: {
				click: function(e) {
					if(e) e.stop();
					stop();
					show(i);
				}
			},
			styles: {
				left: ((i + 1) * (tocWidth + 10))
			}
		}).inject(container));
		if(i > 0) { img.set('opacity',0); }
	});
	
	/* new: control: next and previous */
	var next = new Element('a',{
		href: '#',
		id: 'next',
		text: '>>',
		events: {
			click: function(e) {
				if(e) e.stop();
				stop(); show();
			}
		}
	}).inject(container);
	var previous = new Element('a',{
		href: '#',
		id: 'previous',
		text: '<<',
		events: {
			click: function(e) {
				if(e) e.stop();
				stop(); show(currentIndex != 0 ? currentIndex -1 : images.length-1);
			}
		}
	}).inject(container);
	
	/* new: control: start/stop on mouseover/mouseout */
	container.addEvents({
		mouseenter: function() { stop(); },
		mouseleave: function() { start(); }
	});
	
	/* start once the page is finished loading */
	window.addEvent('load',function(){
		start();
	});
});

I told you it changed quite a bit, didn't I? Here's what I added:

  • I created start, stop, and show functions which do exactly as they're named.
  • Injected table of contents links based upon the number of elements in the slideshow. Each TOC link has a click event which skips to the corresponding slide.
  • Created next and previous links to move forward and backward in the show.
  • Added mouseenter and mouseleave events to stop and start the show when the user triggers each event.

The added code blocks were very simple to add; taking them one at a time kept creating these enhancements quick.

What's Next?

The next step will be transforming the above MooTools JavaScript code into a class. Class-ifying the code will make it cleaner and more organized.

Recent Features

  • By
    Create Namespaced Classes with MooTools

    MooTools has always gotten a bit of grief for not inherently using and standardizing namespaced-based JavaScript classes like the Dojo Toolkit does.  Many developers create their classes as globals which is generally frowned up.  I mostly disagree with that stance, but each to their own.  In any event...

  • By
    9 Mind-Blowing Canvas Demos

    The <canvas> element has been a revelation for the visual experts among our ranks.  Canvas provides the means for incredible and efficient animations with the added bonus of no Flash; these developers can flash their awesome JavaScript skills instead.  Here are nine unbelievable canvas demos that...

Incredible Demos

  • By
    Web Notifications API

    Every UI framework has the same set of widgets which have become almost essential to modern sites: modals, tooltips, button varieties, and notifications.  One problem I find is each site having their own widget colors, styles, and more -- users don't get a consistent experience.  Apparently the...

  • By
    HTML5 Datalist

    One of the most used JavaScript widgets over the past decade has been the text box autocomplete widget.  Every JavaScript framework has their own autocomplete widget and many of them have become quite advanced.  Much like the placeholder attribute's introduction to markup, a frequently used...

Discussion

  1. Nice post. Looking forward to part 3. Thanks David.

  2. Braxo

    In your javascript, line 19, it seems a bit unnecessary to have it so complicated.

    I would argue, for sake of your readers having to re-read that line 5 times to get the gist of its purpose, to break it apart just for readability reasons. Especially because it’s posted in a tutorial.

    I have nothing wrong with ternary operator, I use them myself (and it seems I do more and more with everything I write). But you also included assignments and even nested another ternary in it!

    Maybe instead of removing it or changing it, provide a paragraph describing what that line does. This way your more advanced audience can still see a challenging line of javascript code, but it will also help your more novice readers.

  3. Hi David,

    Nice post, ty.

    I’ve changed it a little: http://gtwebdesignnl/slider/slidertesthtml

    now i can use it for text too.

  4. Nice script… I am about to try it out anyway. I have previous ways of doing ma slide doe but just wanna try out this from mo tools.

  5. Ahmed

    Y0 David, how about having html/div instead of images for the slider, you think it would work?

  6. @Ahmed: Yes, absolutely!

  7. Ahmed

    @David Walsh: Lovely, would you please share a code that uses divs instead of images? I’ve been looking for this for a “while”

  8. Just what I want. Thank you!

  9. Thanks as always David!

  10. Just implemented this for a client. Soooo easy! Thanks a million David!

  11. Yann

    Hello,

    thanks for this !

    i just need to have a fade more slowly, i try more things like {duration: 5000}, but i can’t make it…

    Can you help me ?

  12. Hey David,

    Great tutorials! Your site has been very helpful for me.

    I’m trying to use multiple instances of this on one page but it doesn’t seem to work – is this possible, and if so how would I go about making it work?

    Thanks!

  13. rochelle alder

    I get scripting errors in ie tester. “object expected” which happens on the mouseenter event. In firefox it states undefined object.how do you “correctly” define an object?

  14. This is a great script and very easy to follow instructions. Thanks very much. One thing I am struggling with is to make each slide last longer. Is there a way to do this with the code above? I have looked at the next lesson and although another comment in the thread says that part three includes slide duration, I can’t see how to edit it. Your help would be most appreciated. :-)

  15. Rochelle Alder

    var showDuration = 3000; is the value you would change. 3000 is 3 seconds. If you want it longer, change 3000 to 8000 to make the transition happen after 8 seconds. Play around with it to suit.

  16. Thanks Rochelle. That should have been very obvious. How stupid of me!

  17. I love that users can control the slideshow.

    I’m new with Mootools but I attracted to it with its lightweightness and hopefully can use this app in the future.

    Good job.

  18. Rochelle Alder

    OK so I figured out my problem. I didn’t want the slideshow effect happening with the main image so I commented out the start variable. That resulted in an ‘object not defined’ error.

    So if your variable is not there, but is used within the code, you can expect to get the error in IE but is ignored and runs as it should in firefox although the furebug testing console will tell you there’s an error.

    Thanks David for a great piece of elegant code. Me likey!

  19. bob tipping

    Great script, but no longer works properly with mootools-1.2.4, specifically mouseenter event. It probably requires a very simple change, but I am an absolute beginner and any advice would be greatly appreciated.

  20. bob tipping

    OOps, please disregard my last comment, I had left firebug running by mistake, the script works great with mootools-1.2.4.

  21. Hey David,

    Could the mootools here be tweaked to use a slide transition as opposed to fading?

    Cheers.

  22. Lindy

    Hi
    I was hoping to add a pause button to the controls (rather than pause on mouse over)

    I have added this to the script

    var pause = new Element('a',{
    		href: '#',
    		id: 'pause',
    		text: '||',
    		events: {
    			click: function(e) {
    				if(e) e.stop();
    				}
    		}
    	}).inject(container);
    

    but it doesn’t quite work…

    I also tried

    var pause = new Element('a',{
    		href: '#',
    		id: 'pause',
    		text: '||',
    		events: {
    			click: function() { stop(); }
    		}
    	}).inject(container);
    

    but this got rid of all my controls. Can anyone help?

    • I need pause button. i am not able to get this ?

    • TazNormand

      Hi,
      1st of all i’m french so excuse my bad english ^_^

      here is my contribution for PAUSE button, tested with MooTools core 1.2.5, not working with 1.3 :

      window.addEvent('domready',function() {
        /* settings */
        var showDuration = 3000;
        var container = $('SlideShowPubs');
        var images = container.getElements('img');
        var currentIndex = 0;
        var interval;
        var toc = [];
        var tocWidth = 20;
        var tocActive = 'toc-active';
        var playPause = false;      
      
        /* new: starts the show */
        var start = function() { 
          interval = show.periodical(showDuration);
          $('pause').set('text','||');
        };
        
        var stop = function() {
          $clear(interval);
          $('pause').set('text','>');
          };
      
        /* worker */
        var show = function(to) {
          images[currentIndex].fade('out');
          toc[currentIndex].removeClass(tocActive);
          images[currentIndex = ($defined(to) ? to : (currentIndex  0) { img.set('opacity',0); }
        });
      
        /* new: control: next, pause and previous */
        var next = new Element('a',{
          href: '#',
          id: 'next',
          text: '>>',
          events: {
            click: function(e) {
              if(e) e.stop();
              stop(); show();
            }
          }
        }).inject(container);
        
        var pause = new Element('a',{
            href: '#',
            id: 'pause',
            text: '||',
            events: {
              click: function(e) {              
                if(e) {
                  // switch playPause to true or false depending on its previous state
                  playPause=!playPause;
                  // if TRUE then stop() slideshow, else start() (continue)
                  // TRUE means that user has clicked on the Pause button
                  playPause ? stop(): start();
                }
              }
            }
          }).inject(container);
      
        var previous = new Element('a',{
          href: '#',
          id: 'previous',
          text: '<<',
          events: {
            click: function(e) {
              if(e) e.stop();
              stop(); show(currentIndex != 0 ? currentIndex -1 : images.length-1);
            }
          }
        }).inject(container);
      
        /* new: control: start/stop on mouseover/mouseout */
        /*container.addEvents({
          mouseenter: function() { stop(); },
          mouseleave: function() { start(); }
        });*/
      
        /* start once the page is finished loading */
        window.addEvent('load',function(){
          start();
        });
      });
      

      And don’t forget to put CSS part too :

      #pause {
        position: absolute; 
        bottom: 20px; 
        right: 70px; 
        z-index: 2; 
        display: block; 
        width: 20px; 
        background: #6D84B4; 
        color: #fff; 
        text-align: center; 
        padding: 3px; 
        text-decoration: none;
      }
      
  23. I have used this script and it works well in every browser except Firefox, even 4 and 5.

    The line of code that appears to be the problem in Firefox is:

    images[currentIndex = ($defined(to) ? to : (currentIndex < images.length – 1 ? currentIndex+1 : 0))].fade('in');

    Is there any way to rewrite this code in a different way, even if it means using more lines of code? I think that might resolve the problem in Firefox.

  24. Sorry for the formatting issue.
    I have used this script and it works well in every browser except Firefox, even 4 and 5.

    The line of code that appears to be the problem in Firefox is:

    images[currentIndex = ($defined(to) ? to : (currentIndex < images.length - 1 ? currentIndex+1 : 0))].fade('in');

    Is there any way to rewrite this code in a different way, even if it means using more lines of code? I think that might resolve the problem in Firefox.

  25. Daniel Yee

    @Tony – It’s not a browser issue, but a Mootools version issue. Once I used the same version David used here, it works. The current version of Mootools doesn’t work. Haven’t had a chance to look further as to what changed.

  26. Jonathan Robidas

    Great Tutorial!!! Got me up and running in no times with a cool slider!!!

    Thanks again!!

  27. Hello, thanks for this tutorial, it’s coll

    but i just think that can we use this with carousel sytle? if yes, can you share for its too

    Thanks

  28. Hi David,

    thats the best stuff in the web for mootools, very simple and absolutly great. Can You buiild this slideshow with controlls for the mobile device like iPad (potrait, landscape) and iPhone/Android (portrait, landscape) ?

  29. bob

    Fade out stopped working for me in new mootools core 1.4.4. Is there a bug in the new core ?

  30. bob

    Yes there was a bug. It has been fixed in mootools core 1.4.5.

  31. jitesh

    Excellent topic….really u help me allot thank u…….

  32. Angelus

    window.addEvent('domready',function(){ this is the line I am getting that error: object doesn't support this property or method

    • You must not have MooTools within the page.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!