Posts and Pages Tagged ‘jQuery’

Using the jQuery autosave plugin Last updated:11 January 2015

This article was originally written in 2011 in response to queries about a plugin hosted on the jQuery site, originally written by Raymond Julin. The plugin has subsequently been removed from jQuery and the source code has not been updated since 2010. This article provides an explanation on its usage, and has applied a number of fixes to the original code.

Let’s start with the form – I’m using php to retrieve data from a database and display it in a form for editing. To make the demo worthwhile I’ve added various input elements:

<form action="autosave7.php" method="post">
<fieldset>
<label for="name">Name:<input type="text" name="name" id="name" value="<?php echo $row['name'] ?>"/></label>
<label for="email">Email:<input type="text" name="email" id="email" value="<?php echo $row['email'] ?>" /></label>
<label for="textboxarea">Text:<textarea id="textboxarea" name="textboxarea" rows="2" cols="20"><?php echo $row['textarea'] ?></textarea></label>
<label for="selectfield">Select:<select id="selectfield" name="selectfield">
<option>Option 1</option>
<option>Option 2</option>
</select></label>
<label for="radio1">Radio 1:<input type="radio" name="radios" id="radio1" value="radio1" <?php if ($row['radio']=="radio1") echo "checked='checked'"; ?> /></label>
<label for="radio2">Radio 2:<input type="radio" name="radios" id="radio2" value="radio2" <?php if ($row['radio']=="radio2") echo "checked='checked'"; ?> /></label>
<label for="checkvalue">Check with value attribute:<input type="checkbox" name="checkvalue" id="checkvalue" value="sbtest" <?php if ($row['checkboxvalue'] ) echo "checked='checked'"; ?>/></label>
<label for="check">Check with no value attribute:<input type="checkbox" name="check" id="check" <?php if ($row['checkbox']==1 || $row['checkbox']=='on') echo "checked='checked'"; ?>/></label>
<input type="hidden" name="id" value="<?php echo $row['id'] ?>" />
<input type="submit" value="Save changes" />
</fieldset>
</form>
<p id="message"></p>

I’m including an empty element for the message, just to keep the javascript simple – a more sophisticated solution would append this when required. Now, to add the autosave functionality I need to include this javascript:

$("input,select,textarea").autosave({
			url: "autosave7.php",//set the php file that updates the database
			method: "post",
			grouped: true,//send data for all fields with the autosave
    		       success: function(data) {//on a successful update...
        		$("#message").html("Data updated successfully").show();//...show a message...
				setTimeout('fadeMessage()',1500);//...and then fade it out after an interval
    		},
			send: function(){//on a save...
        		$("#message").html("Sending data....");//..show a message
			},
    		dataType: "html"
		});		
	
       function fadeMessage(){
		$('#message').fadeOut('slow');//just a function to fade out the message
	}

All this just leaves the php to update the database, which is:

if ($_POST['checkvalue']!='false') $checkvalue = $_POST['checkvalue']; 
else $checkvalue = 0;//checkbox with a value attribute
if ($_POST['check']=="true" || $_POST['check']=="on" || $_POST['check']=="checked"  ) $check = 1; 
else $check = 0;//and one without

$qstring="UPDATE test_autosave SET name = '".$_POST["name"]."' ,";
$qstring .= " email = '".$_POST["email"]."',";
$qstring .= " textarea = '".$_POST["textboxarea"]."',";
$qstring .= " selectfield = '".$_POST["selectfield"]."',";
$qstring .= " checkbox = ".$check.",";
$qstring .= " radio = '".$_POST["radios"]."',";
$qstring .= " checkbox = '".$check."',";
$qstring .= " checkboxvalue = '".$checkvalue."'";
$qstring .= " WHERE id =".$_POST['id']."";

mysql_query($qstring);

Because jQuery 1.6 changed the way form elements are posted by the autosave plugins, the autosave plugin itself will not work correctly with this and later versions of jQuery where radio buttons are used. A small change is needed to the plugin to cope with this – you can download the amended version here: jQuery autosave plugin

Inevitably, there’s a working demo here – just to make it more obvious the demo includes a snapshot of the database itself to show the updates.

A few people have asked for copies of the php files used in the demo – so here they are as text files:

Updated 07/05/2014 to cope with value attributes on checkbox fields

Simple jQuery image crossfade Last updated:4 August 2014

I wanted a simple jQuery crossfade effect for an image cycler last week, and surprisingly couldn’t find anything suitable. So I ended up writing my own, and here it is. Tested in IE6/7/8, Firefox 3, Chrome, Opera 9/10, Safari 4, all on Windows XP, IE8/9, Firefox, Chrome and Safari 5 on Win 7, Safari 5 on Mac OS X/Snow Leopard, and Android Browser and Dolphin on Android.

The demo

Hoverfly on a green leaf Fly on a pink flower Insect on a leaf Fly

This basic demo page will show you exactly what’s needed.

The code

You need the following basic html:

<div id="cycler">
<img class="active" src="image1.jpg" alt="My image" />
<img src="image2.jpg" alt="My image" />	
<img src="image3.jpg" alt="My image" />	
<img src="image4.jpg" alt="My image" />		
</div>

Here’s the necessary css – just to show the z-index and positioning – you’ll need to add some more to position as required. Depending on your layout you may also need to set the height and width on #cycler to match your images:

#cycler{position:relative;}
#cycler img{position:absolute;z-index:1}
#cycler img.active{z-index:3}

And here’s the javascript:

function cycleImages(){
      var $active = $('#cycler .active');
      var $next = ($active.next().length > 0) ? $active.next() : $('#cycler img:first');
      $next.css('z-index',2);//move the next image up the pile
      $active.fadeOut(1500,function(){//fade out the top image
	  $active.css('z-index',1).show().removeClass('active');//reset the z-index and unhide the image
          $next.css('z-index',3).addClass('active');//make the next image the top one
      });
    }

$(document).ready(function(){
// run every 7s
setInterval('cycleImages()', 7000);
})

The logic

All the images are loaded with the page and positioned absolutely on top of each other, all with z-index=1. One image is initially set with a class of “active”, which is positioned on the top of the stack with z-index = 3.

Then, using jQuery, I’m identifying the active image, and then the next image down. I’m doing this via the jQuery .next() method. If there isn’t a next image – if we’re at the end of the images – I’m selecting the first image instead using .first().

Now, once I’ve identified the next image, I’m assigning z-index=2 to this so it’s the second image down in the pile – and hence is visible when the top image fades out.

Then, I’m fading out the active image. When this completes there’s a few things to do. First, I’m setting the z-index of the active image (now faded out) back to z-index=1. Then, I’m reversing the fade by using the show() method. It won’t be visible now because of the z-index. Finally, I’m removing the active class. Effectively, I’m putting this image back into the bottom pile.

Nearly there. Then, with the next image, which is now on top anyway, I’m assigning z-index=3, and then adding the active class to this image.

Finally, all of this code is sitting in a function which I’m calling every seven seconds via setInterval().

Responsive version

Making this responsive (without media queries, which is what this page uses) is pretty striaghtforward. The trick is to use a ‘base’ image which is not absolutely positioned to set the dimensions of the cycler and then apply a max-width to #cycler. The base image is then cloned and the cloned version is faded in and out. Have a look at the responsive demo here.

Help! It doesn’t work

If you hit problems, start off by looking at my beginners’ guide to debugging jquery. Most of the problems encountered by users are listed here.

Can I use this on my site?

Probably. See my policies on using code from this site.

Variations on the basic crossfade

Here are a few variations, mostly built in response to questions or comments on the basic code. View the source to see how they’re done.

Cycle through images once and then stop

Multiple cyclers on a page (with a common periodicity)

Multiple cyclers on a page (with different periodicity)

Multiple cyclers with slideshow controls

Cycler with variable timings

Cycle divs instead of images

Superimpose text on the cycler

Cycler with fadeout transition

Crossfade images, no slideshow

Gallery with thumbnails

Cycling a background image with jQuery Last updated:4 August 2014

I had a question last week about whether my crossfade cycler could instead cycle a background image. Now, cycling the background image on an element I think would be very messy indeed, among other reasons because only one background image is widely supported.

However, by setting up a div to act as a background, and cycling the images within that div, I found the effect of cycling the background can be achieved quite simply. The code is virtually the same as the crossfade cycler.

I’m hiding the background div as soon as it’s created, and then fading it back in once all the images are loaded to avoid any jerky transitions. If the user has javascript disabled then just the initial image is displayed as a background – which is a “graceful degradation” I think.

I started my html by including the background div:

<body>

<div id="background_cycler" >

<script type="text/javascript">
$('#background_cycler').hide();//hide the background while the images load, ready to fade in later
</script>

<img class="active" src="/images/misc/backgrounds/background_1.jpg" alt=""/>
<img src="/images/misc/backgrounds/background_2.jpg" alt=""   />
<img src="/images/misc/backgrounds/background_3.jpg" alt=""  />
<img src="/images/misc/backgrounds/background_4.jpg" alt=""/>		
<img src="/images/misc/backgrounds/background_5.jpg" alt=""  />
</div>

rest of html...

Here’s the required css:

#background_cycler{padding:0;margin:0;width:100%;position:absolute;top:0;left:0;z-index:-1}
#background_cycler img{position:absolute;left:0;top:0;width:100%;z-index:1}
#background_cycler img.active{z-index:3}

Setting width:100% for the background div ensures it’ll take up the width of the page – but you could position it differently if needed. Here’s the javascript:

function cycleImages(){
      var $active = $('#background_cycler .active');
      var $next = ($('#background_cycler .active').next().length > 0) ? $('#background_cycler .active').next() : $('#background_cycler img:first');
      $next.css('z-index',2);//move the next image up the pile
	  $active.fadeOut(1500,function(){//fade out the top image
	  $active.css('z-index',1).show().removeClass('active');//reset the z-index and unhide the image
      $next.css('z-index',3).addClass('active');//make the next image the top one
      });
    }

    $(window).load(function(){
		$('#background_cycler').fadeIn(1500);//fade the background back in once all the images are loaded
		  // run every 7s
		  setInterval('cycleImages()', 7000);
    })

And that’s it really – you can see a demo here. I’ve tested in IE6, IE7, IE8, FF3, Safari 5, Opera 11 and Chrome, all on Windows 7.

How do I make this work on a responsive design?

This is fairly straightforward. If we set the images as div background, and then cycle the divs, we can use background-size:cover to ensure the image fits as best as possible. This works fine in IE9+. Have a look at this demo to see it working.

Can I use this on my site?

Probably. See my policies on using code from this site.

Vertical scrollbar using jQuery UI slider Last updated:4 March 2014

Also available as a jQuery plugin.

Here’s my attempt at using jQuery UI Slider as a vertical scrollbar. I began this in 2010 by adapting the code on the jQuery UI site for a horizontal slider. This worked, but seemed unnecessarily complex, so I had another go, starting from the vertical slider code. Since then I’ve had numerous requests for different variations on the basic scrollbar, and these are all now incorporated into a single piece of code.

The code assumes a div with fixed height (#scroll-pane or .scroll-pane in my examples) which contains the content for scrolling. The script wraps the contents of the div to be scrolled in another div (.scroll-content) which is used positioned absolutely, and then the top value of #scroll-content is changed via the slider to make the content scroll up and down. The scrollbar itself is positioned within #scroll-pane, using absolute positioning on the right hand side, but it can go anywhere you like.

There’s a fundamental aspect of the way the vertical slider works which took me a little time to get my head round, and that’s that the slider as a default starts from zero at the bottom and increases upwards – which is the wrong way round for a vertical scroller, hence the need for a bit of extra calculation.

So, here’s the css:

#scroll-pane,.scroll-pane{position:relative}
.scroll-content {position:absolute;top:0;left:0}
.slider-wrap{position:absolute;right:0;top:0;background-color:lightgrey;width:20px;border-left:1px solid gray;}
.slider-vertical{position:relative;height:100%}
.ui-slider-handle{width:20px;height:10px;margin:0 auto;background-color:darkgray;display:block;position:absolute}
.ui-slider-handle img{border:none}
.scrollbar-top{position:absolute;top:0;}
.scrollbar-bottom{position:absolute;bottom:0;}
.scrollbar-grip{position:absolute;top:50%;margin-top:-6px;}
.ui-slider-range{position:absolute;width:100%;background-color:lightgrey}

and here’s the javascript. For convenience I’ve wrapped all the code needed for all the different variations below into one function called setSlider().

function setSlider($scrollpane){//$scrollpane is the div to be scrolled
	
	//set options for handle image - amend this to true or false as required
	var handleImage = false;
	
	//change the main div to overflow-hidden as we can use the slider now
	$scrollpane.css('overflow','hidden');
	
	//if it's not already there, wrap an extra div around the scrollpane so we can use the mousewheel later
	if ($scrollpane.parent('.scroll-container').length==0) $scrollpane.wrap('<\div class="scroll-container"> /');
	//and again, if it's not there, wrap a div around the contents of the scrollpane to allow the scrolling
	if ($scrollpane.find('.scroll-content').length==0) $scrollpane.children().wrapAll('<\div class="scroll-content"> /');
	
	//compare the height of the scroll content to the scroll pane to see if we need a scrollbar
	var difference = $scrollpane.find('.scroll-content').height()-$scrollpane.height();//eg it's 200px longer 
	$scrollpane.data('difference',difference); 
	
	if(difference<=0 && $scrollpane.find('.slider-wrap').length>0)//scrollbar exists but is no longer required
	{
		$scrollpane.find('.slider-wrap').remove();//remove the scrollbar
		$scrollpane.find('.scroll-content').css({top:0});//and reset the top position
	}
	
	if(difference>0)//if the scrollbar is needed, set it up...
	{
		var proportion = difference / $scrollpane.find('.scroll-content').height();//eg 200px/500px
		
		var handleHeight = Math.round((1-proportion)*$scrollpane.height());//set the proportional height - round it to make sure everything adds up correctly later on
		handleHeight -= handleHeight%2; 
		
		//if the slider has already been set up and this function is called again, we may need to set the position of the slider handle
		var contentposition = $scrollpane.find('.scroll-content').position();	
		var sliderInitial = 100*(1-Math.abs(contentposition.top)/difference);
		
		if($scrollpane.find('.slider-wrap').length==0)//if the slider-wrap doesn't exist, insert it and set the initial value
		{
			$scrollpane.append('<\div class="slider-wrap"><\div class="slider-vertical"><\/div><\/div>');//append the necessary divs so they're only there if needed
                        sliderInitial = 100;
		}
		
		$scrollpane.find('.slider-wrap').height($scrollpane.height());//set the height of the slider bar to that of the scroll pane
		
		//set up the slider 
		$scrollpane.find('.slider-vertical').slider({
			orientation: 'vertical',
			min: 0,
			max: 100,
			range:'min',
			value: sliderInitial,
			slide: function(event, ui) {
				var topValue = -((100-ui.value)*difference/100);
				$scrollpane.find('.scroll-content').css({top:topValue});//move the top up (negative value) by the percentage the slider has been moved times the difference in height
				$('ui-slider-range').height(ui.value+'%');//set the height of the range element
			},
			change: function(event, ui) {
				var topValue = -((100-ui.value)*($scrollpane.find('.scroll-content').height()-$scrollpane.height())/100);//recalculate the difference on change
				$scrollpane.find('.scroll-content').css({top:topValue});//move the top up (negative value) by the percentage the slider has been moved times the difference in height
				$('ui-slider-range').height(ui.value+'%');
		  }	  
		});
		
		//set the handle height and bottom margin so the middle of the handle is in line with the slider
		$scrollpane.find(".ui-slider-handle").css({height:handleHeight,'margin-bottom':-0.5*handleHeight});
		var origSliderHeight = $scrollpane.height();//read the original slider height
		var sliderHeight = origSliderHeight - handleHeight ;//the height through which the handle can move needs to be the original height minus the handle height
		var sliderMargin =  (origSliderHeight - sliderHeight)*0.5;//so the slider needs to have both top and bottom margins equal to half the difference
		$scrollpane.find(".ui-slider").css({height:sliderHeight,'margin-top':sliderMargin});//set the slider height and margins
		$scrollpane.find(".ui-slider-range").css({bottom:-sliderMargin});//position the slider-range div at the top of the slider container
		
		//if required create elements to hold the images for the scrollbar handle
		if (handleImage){
			$(".ui-slider-handle").append('');
			$(".ui-slider-handle").append('');
			$(".ui-slider-handle").append('');
		}
	}//end if
		 
	//code for clicks on the scrollbar outside the slider
	$(".ui-slider").click(function(event){//stop any clicks on the slider propagating through to the code below
		event.stopPropagation();
	});
	   
	$(".slider-wrap").click(function(event){//clicks on the wrap outside the slider range
		var offsetTop = $(this).offset().top;//read the offset of the scroll pane
		var clickValue = (event.pageY-offsetTop)*100/$(this).height();//find the click point, subtract the offset, and calculate percentage of the slider clicked
		$(this).find(".slider-vertical").slider("value", 100-clickValue);//set the new value of the slider
	}); 
	
		 
	//additional code for mousewheel
	if($.fn.mousewheel){		
	
		$scrollpane.parent().unmousewheel();//remove any previously attached mousewheel events
		$scrollpane.parent().mousewheel(function(event, delta){
			
			var speed = Math.round(5000/$scrollpane.data('difference'));
			if (speed <1) speed = 1;
			if (speed >100) speed = 100;
	
			var sliderVal = $(this).find(".slider-vertical").slider("value");//read current value of the slider
			
			sliderVal += (delta*speed);//increment the current value
	 
			$(this).find(".slider-vertical").slider("value", sliderVal);//and set the new value of the slider
			
			event.preventDefault();//stop any default behaviour
		});
		
	}
	
}

I’ve tested this on: IE6, IE7, IE8, FF3.6, Safari 4, Chrome and Opera9/10/11 on Win/XP; IE8, IE9, FF9/10, Opera 11, Safari 5 and Chrome on W7; FF7, Epiphany and Chromium on Ubuntu; and Safari 5 on Mac OS X/Snow Leopard. See the demos below for various applications and uses.

Can I use this on my site?

Probably. See my policies on using code from this site.

Please don’t link directly to the javascript on my site. Due to the number of hits on my bandwidth because people were doing this I’ve had to deny direct access to javascript files. Use a CDN like Google’s instead.

Touch screens: As it stands, this will not work with touch screens as jQuery UI does not itself support touch events. I have done only limited testing, but TouchPunch seems to work on an iPad and iPhone, but not on earlier Android devices. See here for some limited testing results – please let me know of anything you have to add to this.

Help! It doesn’t work

If you hit problems, start off by looking at my beginners’ guide to debugging jquery. Most of the problems encountered by users are listed here.

Demos

Basic scrollbar: Demo

setSlider($('#myElement'));

Multiple scrollbars: Demo

$('.myElementClass').each(function(){
	setSlider($(this));
});

Originally added after these two questions within days of each other.

Changing the contents after load: add or remove content within the scrolled element Demo

setSlider($('#myElement'));

function changeContent{//do whatever you want....
...code to change content....
setSlider($('#myElement'));//call the function again to reset the slider for the new content
}

Originally in response to this comment, the slider code will check for the existence of a slider, remove it if it’s no longer required (or establish it if it’s newly required), and aslso set the slider position to match any previous scroll point.

Scrollbar resizes with window: Demo

setSlider($('#myElement'));

$(window).resize(function() {
	setSlider($('#myElement'));
});

originally in response to Igor’s comment, this supports a percentage height .scroll-pane and resizes with the viewport resize. Again, the solution is to call setSlider() on a window resize event.

Scrollbar on a div that’s originally hidden Demo

$('#myElement').show();//or whatever you want, then...
setSlider($('#myElement'));//...call the function again to reset the slider for the new content
}
});

When the div is originally hidden – for example via display:none, most browsers will read it as having zero height and hence all the caslculations decide that a scrollbar isn’t needed. The solution to this just to call setSlider() (again) when the hidden div is displayed.

Preset the scroll position on load: Demo

setSlider($('#myElement'));

//code to set an initial scrolled position
var position = $("#targetElement").position();//find the position of the required item
var topValue = position.top;//extract the top value
var sliderValue = 100-(100*topValue/($(".scroll-content").height()-$("#scroll-pane").height()));//calculate the percentage of the top of the required item
$(".slider-vertical").slider("value", sliderValue);//and set the new value of the slider

Autocomplete: scroll to an item selected from a database Demo Fuller explanation

setSlider($('#myElement'));
//autocomplete
var difference = $(".scroll-content").height()-$("myElement").height(); 
$("#quickfind").autocomplete({
	source: "get_descriptions.php",
	minLength: 2,//search after two characters
	select: function(event,ui){
		position = $(".scroll-content-item:contains("+ui.item.value+")").position();//search for a div containing the selected description and read its position
		
		var topValue = -(position.top);//content top is just the negative of the top position
		
		if (topValue>0) topValue = 0;//stop the content scrolling down too much
		if (Math.abs(topValue)>difference) topValue = (-1)*difference;//stop the content scrolling up too much
	
		sliderVal = (100+(topValue*100/difference));//calculate the slider position from the content position
		$(".slider-vertical").slider("value", sliderVal);//set the slider position
		}
});

Originally in response to Dan’s comment.

Scroll automatically on load: have the element scrolling without user input Demo

setSlider($('#myElement'));

var scrollId = setInterval('scrollDown()', 60);// start the autoscroll via a function

$(".ui-slider-handle").mouseover(function(){//stop the autoscroll if the handle is hovered
    clearInterval(scrollId);
});

function scrollDown(){
	if ($(".slider-vertical").slider("value")>0){//if it's not at the bottom, scroll down
		$(".slider-vertical").slider("value",$(".slider-vertical").slider("value")-1);
	}
}

Originally in response to this comment. Can’t quite see the application of this one either…

Scrolling with buttons: Demo

setSlider($('#myElement'));

$('#arrow_up').mousedown(function(event) {
	if(event.preventDefault) event.preventDefault();
    intervalId = setInterval('scrollUp()', 30);
	$(this).bind('mouseup mouseleave', function() {
		clearInterval(intervalId);
	});
});
$('#arrow_down').mousedown(function(event) {
	if(event.preventDefault) event.preventDefault();
    intervalId = setInterval('scrollDown()', 30);
	$(this).bind('mouseup mouseleave', function() {
		clearInterval(intervalId);
	});
});

function scrollUp(){
	if ($(".slider-vertical").slider("value")<100){//if it's not at the top, scroll up
		$(".slider-vertical").slider("value",$(".slider-vertical").slider("value")+1);
	}
}
function scrollDown(){
	if ($(".slider-vertical").slider("value")>0){//if it's not at the bottom, scroll down
		$(".slider-vertical").slider("value",$(".slider-vertical").slider("value")-1);
	}
}

#arrow_up and #arrow_down are the ids for the arrow buttons, although you’d probably guessed that…Originally in response to this comment. Dick pointed out that if you try and drag the scrolling buttons it can occasionally cause the scroller to break. I couldn’t recreate this at all, but added some code to prevent the buttons being dragged, which Dick confirms fixes the problem.

Scrolling to anchors: Demo

setSlider($('#scroll-pane'));

$('#anchors a').click(function(){

	var difference = $('.scroll-content').height()-$('#scroll-pane').height();//calculate the difference - not needed if within the main slider code
	
	var targetclass = ($(this).attr('class'));//read the class of the clicked anchor
    
	var position = $(".scroll-content ."+targetclass).position();//search for a div with matching class and read its position
    var topValue = -(position.top);//content top is just the negative of the top position
		
	if (topValue>0) topValue = 0;//stop the content scrolling down too much
	if (Math.abs(topValue)>difference) topValue = (-1)*difference;//stop the content scrolling up too much

	sliderVal = (100+(topValue*100/difference));//calculate the slider position from the content position
	$(".slider-vertical").slider("value", sliderVal);//set the slider position
	
	return false;
});

This assumes markup where the anchors are assigned a class which is also added to the ‘target’ scroll point within the div. View source for the details.

Easing: animate the slider using easing Demo

Had a couple of comments asking about easing. It doesn’t work well with the code as it is, because the bar scrolls at every mouse move. However, if the slider code is changed to call the animation on the change event instead of the slide event, then it is possible, although the scrolled content will not move until the slider is stopped. I don’t care for this one at all, although it does work better with anchors.

Note that this (the only demo that) uses a different version of setSlider(), where the slider is instantiated via:.

   //set up the slider 
   $scrollpane.find('.slider-vertical').slider({
      orientation: 'vertical',
      min: 0,
      max: 100,
	  range:'min',
      value: sliderInitial,
      change: function(event, ui) {
			 var topValue = -((100-ui.value)*difference/100);
			 $scrollpane.find('.scroll-content').[highlight]animate({top:topValue},animateSpeed,easingMethod[/highlight]);//move the top up (negative value) by the percentage the slider has been moved times the difference in height
			 $('ui-slider-range').height(ui.value+'%');
	  }	  
   });

You need to set the variables animateSpeed and easingMethod, of course, and include the easing plugin.

Shopping cart: with jQuery UI draggable/droppable Demo

setSlider($('#myElement'));
$('.item').draggable({appendTo:'body',helper:'clone'});
$('#droppable').droppable({
	drop:function(event,ui){
		$( this ).find( "#placeholder" ).remove();
		var description = ui.draggable.find('p').text();
		$( "<\li><\/li>" ).text(description).appendTo( $('#droppable ul') );
	}
});

originally in response to Juan’s comment, minimal droppable code to to allow dragging from the scrolling div and dropping into a basket.

Autohide scrollbar: so it’s displayed only on hover Demo

setSlider($('#myElement'));
$(".slider-wrap").hide();
$("#myElement").hover(function(){
	$(".slider-wrap").show();
	},
	function(){
	$(".slider-wrap").hide();
});

Robert asked about an autohide function. I really don’t like it…

Styling the handle Demo

setSlider($('#myElement'));

plus these settings within setSlider():

function setSlider($scrollpane){//$scrollpane is the div to be scrolled
	
	//set options for handle image - amend this to true or false as required
	var handleImage = [highlight]true[/highlight];
         
        ...

	if (handleImage){//change the image paths as required for your images - delete any that are not required if you want
		$(".ui-slider-handle").append('');			
                $(".ui-slider-handle").append('');
		$(".ui-slider-handle").append('');
	}

        ...

and this addtional css

.ui-slider-handle{background:transparent url(/images/misc/scrollbar-handle-middle.png) repeat-y top left;}

In order to make this example bulletproof, I’ve used four images (!) – one each for the top and bottom of the handle, one for the white ‘grip’ in the middle, and one for the rest set via the css. Although this feels a bit over the top it works for a scrollbar of any length. In order to do this the code optionally appends three images into the scrollbar handle html after instantiating the slider.

Styling the scrollbar Demo

This is just an additional piece of css:

.slider-wrap{background-color:#EA9531;}

Originally in response to this question this allows one side of the scrollbar to extend – easier to view than describe.The slider already adds an extra element .ui-slider-range which in the standard css is coloured the same as the scrollbar background – so it’s just a question of changing one of these. IE6 does odd things during the scroll though, which I can’t fix, suggestions welcome.

Changelog

6 March 2012 – consolidated all variations to use standard code

Mostly in order to make keeping these things up to date a bit easier, I’ve consolidated all the different variants to use a single version of code, which supports everything. There’s no real change to the mechanics of the slider, just how it’s packaged up. Also tidied up two bits of ancillary code, specifically on the scrolling with buttons example.

28 February 2012 – upgrade to jQuery/UI/mousewheel

I’ve upgraded all the demos to use jQuery 1.7.1, jQuery UI 1.8.14 and Mousewheel 3.0.6. At the same time I’ve wrapped the mousewheel code in a conditional to stop any errors if the mousewheel plugin is not loaded, and amended the mousewheel code so that it copes better with variances in the scrolled content – the previous code resulted in a 5% vertical shift on a mousewheel rotate – this now varies dependent on the difference in size between the scrolling element and its content.

10 January 2012 – tweaks to mousewheel code

I’ve amended the mousewheel code in three examples where the slider set up may be called more than once, as previously repeated calling of the code resulted in very fast mousewheel scrolling. Examples affected are Add Content, Window Resize and Hidden Divs.

9 November 2011 – packaged as a plugin

Finally packaged this up as a plugin.

1 March 2011 – improved handling of clicks outside handle and mousewheel

In the process of sorting out the Opera issues below, I’ve made a couple of improvements. Previously, clicks beyond the handle, and beyond the actual slider (which is less high than #slider-wrap to accommodate the handle) weren’t handled very well, and didn’t work in IE. They do now, by looking at the point at which the click was made and moving the slider appropriately. This replaces the changes made 16 January 2011. I’ve also simplified the mousewheel code to move #scroll-content from the slider by using the change option – see the code above, which replaces original code added 4 August 2010. These changes are now applied to all the demos.

27 February 2011 – amendments for Opera 11 issues

Following a contact from a user reporting difficulties with Opera 11 when resizing the scroll content, I have amended the demos for both this and for the multiple slider. Opera 11 doesn’t like the scrollbar being absolutely positioned, it seems, so all demos are now updated to position the scrollbar differently. This doesn’t significantly affect the javascript. This wasn’t an issue with Opera 9 or Opera 10. Makes a change from IE messing things up I suppose…

16 January 2011 – handle clicks at top and bottom of the scrollbar correctly

Ohm-ish points out that clicks on the top and bottom of the scrollbar, outside the handle, do not result in a scroll. This is because the slider range is restricted to less than the total height of the scrollbar to allow the handle to fit in.

Attempts to use the whole height of the slider work, but then the scrollbar handles doesn’t track the mouse correctly. Experimentation shows that adding .ui-slider-range sorts clicks above the slider range – this needs the following css:

.ui-slider-range{position:absolute;width:100%}

and I’ve then added a little jQuery to cope with clicks below the slider range:

//position the slider range div at the top of the slider wrap - this ensures clicks above the area through which the handle moves are OK
$(".ui-slider-range").css({top:-sliderMargin});

//add a click function to ensure clicks below the area through which the handle moves are OK
$("#slider-wrap").click(function(){//this means the bottom of the slider beyond the slider range is clicked, so move the slider right down
   $("#slider-vertical").slider("value", 0);
   $('#scroll-content').css({top:-difference});   
})

This has now been added to all the demos and the code shown above.

15 November 2010 – ensure the handle height margins are correct

Thanks to Thom for a suggested addition to ensure the handle height is exactly divisible by two. Without this, browsers other than FF show a 1px gap under the slider handle when it’s at the bottom of the slide.

8 November 2010 – allow for the scrollbar not being required

Following Jorge’s question below, I’ve amended the code slightly so that the slider is only added if it’s needed (if the height of #scroll-content is greater than the height of #scroll-pane), and as part of this added the necessary html for the scroller via jQuery. I’ve also added a line so the height of the scrollbar is set to the height of #scroll-pane.

8 September 2010 – mouse and scrollbar synced correctly

Following Rob’s comment (#5 below) I’ve amended both the css and javascript to fix a problem where the mouse and scrollbar weren’t in sync. Both the code on this page and the demo are updated.

4 August 2010 – mousewheel integration

Following Yves’ comment below I thought I’d have a go with adding mousewheel functionality as well. I used Brandon Aaron’s mousewheel plugin.

Then I’ve added the following additional javascript:

$("document").mousewheel(function(event, delta){

     var speed = 5;//set the speed of the scroll
     var sliderVal = $("#slider-vertical").slider("value");//read current value of the slider
		
     sliderVal += (delta*speed);//increment the current value
 
     $("#slider-vertical").slider("value", sliderVal);//and set the new value of the slider
		
     var topValue = -((100-sliderVal)*difference/100);//calculate the content top from the slider position
		
     if (topValue>0) topValue = 0;//stop the content scrolling down too much
     if (Math.abs(topValue)>difference) topValue = (-1)*difference;//stop the content scrolling up too much
		
     $("#scroll-content").css({top:topValue});//move the content to the new position

     event.preventDefault();//stop any default behaviour

});

I’ve kept this code separate from the rest so you can use it as required. It’s included in the demo page. The mousewheel works anywhere on the page on the demo – to restrict it to operate only on the scrolling div itself the opening statement would be amended to:

$("#scroll-pane,#slider-wrap").mousewheel(function(event, delta){...etc

Debugging jQuery – a beginner’s guide Last updated:18 July 2013

I get quite a lot of questions from users of this site who are trying to implement some jQuery on their pages, and encountering problems in doing so. I’ll start off by listing the things to check first, and then explain how you to use the browser console to help you. If you’re already seeing error messages in your console, start here.

Nothing happens/jQuery doesn’t work – help!

Go through this checklist in order to rule out the most likely issues:

  • Have you included jQuery on your page?

    You need to include a link to jQuery on your page. This is normally (but doesn’t have to be) included in the document head, and will look something like this:

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script>

    If you don’t include jQuery, nothing will work.

  • Have you included jQuery just the once

    Check you’ve only got jQuery loaded once. It’s not uncommon to see it loaded more than once, particularly if you’re trying to use a couple of different plugins. Multiple versions usually, but not always, cause everything to fail.

  • Are you calling the scripts in the right order?

    You need to call scripts (as in load them on your page) in the order that you need them. This should be: jQuery, jQuery UI (if you’re using it), and then any code that needs jQuery. If a script that needs jQuery runs before jQuery is loaded, it won’t work.

  • Does your page use .noConflict()

    Err, what….? You’ll probably be aware that jQuery uses the dollar sign as a shorthand – you’ll have seen code like this:

    $('#myselector').fadeOut('slow');

    Now, it’s possible to disable the use of the $ shorthand by using .noConflict(). This is done in case other javascript libraries need to use the $ variable themselves. WordPress applies .noConflict() by default. The result will probably manifest in the same way as not loading jQuery. To fix this, you’ll need to amend your code to look like this throughout:

    jQuery('#myselector').fadeOut('slow');

    Check out the .noConflict documentation for more information on how to use, and work around this.

  • Are you using another javascript library as well as jQuery?

    If you are, the first thing to consider is ‘Why?’. It’s not impossible to do, but you’ll be making things more complex than they need to be, and life harder for yourself. You’ll need to look at .noConflict again.

  • Is your code correct?

    If you’ve mistyped your code or otherwise made an error, then that can cause all the javascript on your page to stop working. If this is the cause, then it’ll usually show as a console error – see below.

  • Is anything else interfering with your code?

    Sometimes, if you have multiple plugins loaded, either in WordPress, or just lots of scripts loaded, they interfere with each other. If this is a possibility, remove the other scripts and see if that solves your problem. If it does, add scripts back one by one until you isolate the cause.

  • It’s none of these….

    Well, at least you’ve ruled out the obvious things. If you’ve got this far, you need to look more closely at your code, see if there are any error messages generated (see below), and take it from there.

Accessing the browser console

Most browsers have a helpful console where any javascript error messages are displayed. These can often give a clue to the problem. Accessing the console varies from browser to browser.

  • Firefox: If you’re using Firebug click the icon to launch Firebug and access the Console tab. You’ll need to load the page after launching Firebug.
  • IE9: Access Developer tools via F12, and then click the Console menu item. You’ll need to reload the page after launching tools.
  • Chrome: Developer tools are Ctrl+Shift+I, then Console tab.
  • Safari: Develop > Start Debugging Javascript
  • Opera: Ctrl+Shift+I to launch Dragonfly, then the Scripts tab (not the Console tab)

Console errors in 15 seconds

Any of the first four issues in the checklist at the top of the page will generate this (or a very similar) error ($ is not defined) – for example (from Chrome):

Chrome console screenshot $ is not defined error

If your javascript/jQuery has a syntax error, then the console will tell you where it is, and what it thinks is wrong. For example (from Firebug):

Firebug console screenshot showing the location and description of a jQuery syntax error

It’s obviously not feasible to list every possible console error here. If you see something in the console that doesn’t make sense to you, the best bet is to copy the message and Google it. Here’s some more information on using the console to debug.