Sometimes, We Write Stuff...

MooTools Content Slider Update - Numbered Nav

27 comments

So, here we are again... yet another content slider update!  By far, the most requested addition I have received is a way to 'jump' to other slides, along with a navigation for it.  I'm actually going to take that one step further, and show you how to accomplish that with a dynamically created navigation list!

Overview

This tutorial will build upon the past div slider tutorials on this site, so I'm just going to focus mainly on the creation/functionality of our new numbered nav.  (If you haven't gone over those yet, I highly recommend that you glance over them to get familiar with everything.)   In particular, I will be explaining the use of the 'element.adopt' method, the dynamic creation of html elements and their contents, and then the code to tie it all into our original slider.  I'll also add in a little code that prevents a graphical glitch that the past slider was suffering from.  (The 'stuttering' effect that was happening when the prev/next buttons were rapidly pushed.)

As always, I'll try to keep this simple – and please feel free to ask questions, call me a jackass, say thanks, etc. in the comments area!  The full code and example link are located below.

The XHTML

Our XHTML is basically identical to our last tutorial.  I have made two minor changes, though.  First, I've turned our 'controls' div into an unordered list, and assigned the buttons as anchors inside of each list:

<ul id="controls"> 
	<li id="prevbtn"><a>prev</a></li>
	<li id="playbtn"><a>pause</a></li>
	<li id="nextbtn"><a>next</a></li>
</ul>

I've also added another unordered list, with an id of 'num_nav':  (I'll give you one guess what that will be for...)

<ul id="num_nav">
	
</ul>

The CSS

Very little has been changed here.  Other than changing the CSS a bit to handle the controls being inside of list items, the only new addition is the styling/positioning for our numbered navigation.  It's just some basic styling:

#num_nav {
	width: 500px;
	height: 30px;
	position: absolute;
	top:  427px;
	left: 105px;
	list-style: none;
}

#num_nav li {
	display: block;
	float: left;
	width: 20px;
	height: 20px;
	margin: 2px;
	border: 1px solid;
	border-color: #666666;
	background-color: #333333;
}

#num_nav a {
	display: block;
	width: 20px;
	height: 20px;
	line-height: 20px;
	text-align: center;
}

The Javascript/MooTools

This is where the majority of the changes/additions are located, as you can probably imagine. 

Config Area Changes

First, I've added a few important new things to our 'config' area:

var numNav = new Array();  //create an array to hold our dynamically created number navigation
var isSliding = 0;  //will be used to prevent multiple clicking
var numNavHolder = $('num_nav');  //get element for our numbered nav
Dynamic Number Buttons Creation

Now we will dynamically create our numbered navigation items, and then insert them into the 'numNavHolder' that we just defined above.  This makes use of the native 'adopt' method of MooTools Elements, and I think you'll find it quite powerful!  We'll do this in our 'setup' area of the code, inside the setup loop for each slide.  The first thing we'll do is create the anchor element and the list item element.  As we create our anchor element, we'll also give it a class and insert content (the number) into it:

var numItem = new Element('li', {id: 'num'+index});
var numLink = new Element('a', {
	'class': 'numbtn',
	'html': (index+1)
});

Next, we'll use the 'adopt' method to insert our 'numLink' inside the 'numItem' we just created, and then we'll put this new nav item into the 'num_nav' unordered list.  (Think about those wooden Russian dolls... as that's essentially what we're doing here.)  Note that I've also used the javascript function 'push()' here to add each new anchor into an array, which we'll be using in a moment:

numItem.adopt(numLink);  //inserts link into list item
numNavHolder.adopt(numItem);  //inserts link item into the numbered nav
numNav.push(numLink); //push element into an array, for accessing later

Lastly, we'll highlight our initial active button:

var initNum = numNav[itemNum];
origColor = initNum.getStyle('color');  //get original link color
initNum.setStyles({
	'background-color': '#272727',
	'color': '#FF6600'
});
Updated Movement Function

In order to keep this small and easy-to-understand, I condensed the animation functions into a single function called 'slideMove'  It's nearly identical to the previous 'slideForward' and 'slideBackward' functions from the earlier tutorials, except that it accepts two parameters, direction and passedID.  Direction is required, and as you may have guessed it tells our movement function 'how' to move – 0 is for backward, 1 is for forward, and 2 is for a direct jump to a number.  (Obviously, the 'passedID' parameter is only required when direction=2.)  Here's a look at the entire 'slideMove' function:

var slideMove = function(direction, passedID){ 
	
	//get item to slide out
	var curItem = items[itemNum]; 
	var curNumItem =  numNav[itemNum];
	
	//change index based on value of 'direction' parameter
	if(direction == 1){
		if(itemNum < (numItems - 1)){
			itemNum++; 
		}
		else{
			itemNum = 0;
		}
	}
	else if(direction == 0){
		if(itemNum > 0){
			itemNum--; 
		}
		else{
			itemNum = (numItems - 1);
		}
	}
	else {
		if(itemNum != passedID){
			itemNum = passedID;
		}
	}
	
	//now get item to slide in using new index
	var newItem = items[itemNum];
	var newNumItem =  numNav[itemNum];
	
	
	//set up our animation stylings for slide
	var item_in = new Fx.Morph(newItem, {
		     duration: transitionTime, 
		     transition: Fx.Transitions.Cubic.easeOut, 
		     link: 'ignore',
		     
		     //click prevention actions
		     onStart: function(){
			    isSliding = 1;  //prevents extra clicks
		     },
		     
		     onComplete: function(){ 
				isSliding = 0;  //allow clicks again
		     }
	});
	
	var item_out = new Fx.Morph(curItem, {
		     duration: transitionTime, 
		     transition: Fx.Transitions.Cubic.easeOut, 
		     link: 'ignore'
	});
	
        //number nav button effects
	var num_in = new Fx.Morph(newNumItem, {
		     duration: 100, 
		     transition: Fx.Transitions.linear, 
		     link: 'ignore'
	});
	
	var num_out = new Fx.Morph(curNumItem, {
		     duration: 100, 
		     transition: Fx.Transitions.linear, 
		     link: 'ignore'
	});
	
	//we will set a beginning value here
	//this is so that it gives the illusion of continuous motion from one direction, even after the first cycle of items
	item_in.start({
	'left': [502, 0]
	});
	
	//no beginning values needed, since we always want to push the old item out to the left
	item_out.start({
	'left': '-502'
	});
	
	num_in.start({
		'background-color': '#272727' ,
		'color': '#FF6600'
	});
	
	num_out.start({
		'background-color': '#333333' ,
		'color': origColor
	});
	
};

Take special notice of the 'onStart' and 'onComplete' events I'm making use of in the item_in animation (FX) setup above.  (These are used to set the 'isSliding' variable's value, which we will use to prevent the extra clicks glitching.)

Hooking Up the Buttons

The next/prev/play buttons are all essentially the same, except for one thing.  Through the use of an 'if' statement, I am checking the 'isSliding' variable to determine whether to perform the movement function or not.  Here's an example with the 'next' button:

nextBtn.addEvent('click', function(){
	if(isSliding == 0){
		if(isPaused == 0){
			$clear(theTimer);
			theTimer = slideMove.periodical(slideTimer, this, 1);
		}
		slideMove(1);
	}
});

The code for the new number navigation is quite similar.  The only difference is that we will be passing the index of the button into our move function, so that it knows what slide to jump to.  I've also set them to change the cursor to 'pointer' on hover, making it more like a button.  Check it out:

numNav.each(function(element, index) {
	var origColor = element.getStyle('color');
	
	element.addEvents({
		'click' : function(){
			if(isSliding == 0 && itemNum != index){
				if(isPaused == 0){
					$clear(theTimer);
					theTimer = slideMove.periodical(slideTimer, this, 1);
				}
				slideMove(2, index);
				//alert("index: " + index);
			}
		},
		'mouseenter' : function() {
			this.setStyle('cursor', 'pointer');
		}
	});

});

Conclusion

And there you have it, a timed content slider with basic controls... and now also with dynamically created slide number buttons!

Demo/Download

  • StumbleUpon It
  • del.icio.us

+ Comments

#1
mark said:
Jul 07, 2008 01:09

This is a pretty cool effect. I've done something like it, but for v1.1 of mootools. Check it out at 8trk.com

#2
Jul 08, 2008 10:51

Really nice... There's only one thing missing in my opinion. The pause effect on a mouseOver event.

I'm trying to add it but with no success. Can Someone try it?

#3
mark said:
Jul 08, 2008 10:43

@Raff

If it were written as a class, it would be a lot easier[cleaner] to $clear the timer.

You would have methods that look like

buttonAction: function(){} //where all of the events for the buttons would be defined

startTimer: function(){}, endTimer: funciton(){},

In your buttonActions method, you can do a mouseover[mouseenter is better] for the buttons that would call the endTimer method, and have a mouseout[mouseleave] event that would start the timer again.

Writing it as a class would make it infinitely more flexible than what you currently have.

#4
Daniel said:
Jul 09, 2008 01:39

Hi Mark, you are absolutely correct about this being more clean/flexible as a class. I think that should probably be the next (and final) tutorial in this 'slider' series. (This started out as a simple timed slideshow, and I honestly had not planned on taking it this far...* grin *)

#5
smile4o said:
Jul 15, 2008 02:44

Hello, first of all I'm sorry for my bad english. Second, I have a question. How about if replace li's content in num_nav with thumbnails, and make really cool looking gallery? I was trying to do something like that, but with no good result :(. It'll be interesting for me to know is it possible, or it is not a good idea. Thanks in advance.

#6
Daniel said:
Jul 17, 2008 01:23

Hello smile – your English is just fine, no worries! smile

As for your question: It would be possible to do that, but I know there are much better MooTools scripts/classes out there for creating image galleries.

One of my next posts will be a list of quality MooTools classes/scripts... so I will be sure to include a gallery or two! (I hope to make that post sometime this weekend.)

#7
speedy said:
Jul 17, 2008 03:01

Hi Daniel! Your script is great and one of the best ones I could find specially for Mootools 1.2 smile The script is working fine but I have 1 problem : I don't want the number tabs in my slider so I remove the

<ul id="num&#95;nav">      
</ul>

from the html but after that the slider stops working :(

Is there a way to make this work like it does right now with the num-nav removed ?

Thanks smile

#8
speedy said:
Jul 17, 2008 03:22

Daniel don't bother about my previous comment. I didn't notice that you had 3 versions of this script

I'm a satisfied guy now.... just got it like I wanted!

Just 1 last "wish" :D As I'm using your control_slider script so there is no num-nav in that one, this means that after we have slided through all the elements we go back to number 1 element... Now in this one we see the number 1 highlighted once again which shows us that we are on element 1..

Now in the other slider where there is no num-nav we never get to know which element we are in, is there a way to show some other kind of effect after we come back to the first element ? Nothing really important, but if you ever plan to work more on this then please keep this in mind

Thanks smile You're my hero!

#9
smile4o said:
Jul 18, 2008 05:18

Hello, Daniel. Thank You for your answer. And I'll wait for that list. It will be very interesting for me. Have a nice day and smile smile

Daniel said:
Jul 18, 2008 03:30

Speedy and Smile, thanks so much for your pleasant comments! (And I do apologize that I'm so slow to respond... business has been really intense over these last few weeks.)

@Speedy: I probably won't do much more with this until I convert it into a class... but I hope to get to that soon. I think your 'wish' will be fairly easy to accomplish at that point.

@Smile: Yeah, I'll get a nice list put together for us this weekend. You can expect that post on Sunday, more than likely. smile

speedy said:
Jul 20, 2008 04:28

Thanks for your kind reply Daniel You're doing a great job helping pathetic people like me with your great scripts lol smile

Forget about my previous wish... Its not that important

The most tempting thing I see when I visit your site is the fading rollover/hover on the links on the sidebar/download,view demo buttons... I'm trying to learn how to do this for a long time and even more when I saw dragoninteractive.com. Now I know how to do it with images and I was also able to do it with mootools 1.11 using this method : http://demos111.mootools.net/Fx.Styles Now I want to do the same with 1.2 using this method : http://demos.mootools.net/Mouseenter But the problem is that I can't get it to work with more than 1 element as its using IDs for the effect to work... Now as you may have guessed by now that I'm a noob in js/mootools so I can't do it on my own lol I just want to know how we can change it to work with multiple lists like we can do with the 1.11 version.

Sorry for going OT and also for asking to such a busy person like you but I know you are a GREAT guy and will help me when you have nothing else to do and getting bored for hours... after watching every show on the TV, listening all the songs on the iPod if you ever get time please guide me hehe...

Thanks

Daniel said:
Jul 20, 2008 10:57

Hey all, sorry I haven't posted anything yet! Without going into too much detail, let's just say my stomach has been upset this weekend...

I'll be totally covered up Monday and Tuesday, but I should have a little time on Wednesday to finish the article.

speedy said:
Jul 20, 2008 11:25

Hey come on why do you need to be sorry? Lol I mean really you are already cool enough to share you're hard work with us so yea man no sorry worry here smile

On the other side, really sorry to hear that you are not well... I mean I know how much I hate to be ill when I'm working on designing projects lol!

Get well soon mate and please take your time smile

Vojc said:
Jul 28, 2008 02:43

First of all that slide is very cool, and thx for your time to share for us smile

I notice on previous post that Shnoab ask a question so I wonder is any posibility change to verical mode?

"Shoab said: Jul 11, 2008 04:39

How would one go about making this scroll vertically instead of horizontally. "

best regards

Vojc

Daniel said:
Jul 28, 2008 03:39

Hi Vojc (and Shoab) - basically, all you would need to do is change the initialization and the animation to use 'top' instead of 'left'. Hope that makes sense!

Vojc said:
Jul 28, 2008 07:59

thx for quick reply Daniel. So... I look and try changing from left to top but not working for me. I'm litlle dummy about program coding so any sugestion is wellcome... thx again

Vojc

Vojc said:
Jul 28, 2008 09:27

I figure out, I think so. Just add one line of code:


//since the viewer obviously has javascript on, we can remove the 'first_item' class
if(index == 0){
element.removeClass('first_item');
element.setStyle('left', "0");
}
else{
element.setStyle('left', "0");
	element.setStyle('top', "185");
element.setStyle('opacity', "0");
}

and


//this is so that it gives the illusion of continuous motion from one direction, even after the first cycle of items
item&#95;in.start({
'left': [0, 0],
	'top': [185, 0],
'opacity':[0,1]
});

//no beginning values needed, since we always want to push the old item out to the left
item&#95;out.start({
'left': '0',
	'top': '-185',
'opacity':[0]
});

End...

corect me if I'm wrong, please. Thx again for suggestion Daniel.

Vojc said:
Jul 30, 2008 03:39

For those who need to dynamiclly display 2 record in one slide at the time just change some code and that it. This work only for horizontal slider.

  1. Apply horizontal looper with row: all records column: 2 (I used free Tom Muck extension link: http://www.tom-muck.com/extensions/help/HorizontalLooper/)

  2. Apply class="slide_item" into <tr> and delete <div class="slide_item"> amd </div>

  3. change div.slide_item... to tr.slide... in css

  4. That's all. Work for me smile

tobi said:
Jul 30, 2008 11:21

hey there.

first, thanks for that script.. i was using another slider but needed that automatic highlighted numbering thing. perfect.

but i've got one question.

is it possible to remove the autoplay and/or the whole play/pause thing without rewriting the js?

another suggestion would be to style the inner slide in a way that going from slide 1 to slide 5 would actually show the 3 slides in between.

now it's more a content jumper then a slider wink

anyway.. great script.

Daniel said:
Jul 30, 2008 12:28

Tobi, yes it's quite easy to remove the autoplay... just remove the periodical aspect of the slide function.

As for showing the 'in-between' slides during transitions, that would involve setting the items up as a linear 'strip' and then sliding that strip as a whole. (Slightly different setup and execution, but should be easy enough.) Feel free to give it a shot and show everyone your version! smile

tobi said:
Jul 31, 2008 02:10

hehe,

yeah. guess i'll give it a try but it will take some time.. be back with questions.

Beasty said:
Aug 08, 2008 03:42

Nice! But not unobstrusive! No chance to see all "tabs" with javascript deactivated. Should work on that.

Daniel said:
Aug 08, 2008 04:26

@Beasty: Thanks... but I'm curious, honestly who disables Javascript in 2008? Judging from various client sites' stats, I'd have to say virtually none. However, you are welcome to work on it...it's free to download and modify.

Edit: While I'm not concerned about it in this case, Beasty is actually right – if I were using this on a client site and it contained highly important content, I'd probably adjust the original CSS (ditching the overflow:hidden) and re-set it via MooTools when the DOM is ready. wink

Aug 10, 2008 10:01

Raffaele Colleo, You can add

var items&#95;container = $('items&#95;container');

to the config vars and add

items&#95;container.addEvent('mouseover', function(){
        if(isSliding == 0){
            if(isPaused == 0){
                isPaused = 1;
                $clear(theTimer);
                playBtn.getElement('a').set('html', 'play');
            }
        }
     });

     items&#95;container.addEvent('mouseout', function(){
        if(isSliding == 0){
            if(isPaused == 1){
                isPaused = 0;
                theTimer = slideMove.periodical(slideTimer, this, 1);
                playBtn.getElement('a').set('html', 'pause');
            }
        }
     });

to the control buttons.

It works for me ( see http://dev.deridderserver.nl/Matthijs/Test/Slide/ )

NOTE: Replace &#95 ; with an _

Aug 18, 2008 08:12

Is there any way to change the transition type? Basically I want to make the transition a fade-in/fade-out thing.

Anyone know how I can accomplish this?

marcello said:
Aug 20, 2008 10:35

First of all, this is an awesome tutorial. Thank you for creating it. I was playing around with it and I made it smaller and removed the previous/pause/next buttons. Something along the way caused the last slide to be visible until after they have all cycled through the container once. I can't figure out what's causing it, though. Any ideas on what may be causing that and/or how to go about fixing it? Thank you in advance for your advice.

Henrik said:
Aug 24, 2008 07:11

Hey jeremy, the fade-out fade-in effect would be accomplished by simply removing the left attribute from the start function and replace it with opacity[0,1 in the item_in.start function and opacity [0 in item_out.start.

Here's a preview of your comment:

Discuss This Post:

You guessed it... your name goes here.

Have a website? Put it here.

We promise, we won't share your address with ANYONE.


Type your comment here... this box will auto expand!

Note: URLs will be auto-converted to links!

Please enter the word you see in the image.



* - denotes required fields