Marc Neuwirth
From the archive. This post was written in 2010. The demos still run, but the techniques reflect the browsers of that era.

Using a jQuery UI Slider to Select a Time Range

Recently I was trying to create a web form where a user could enter a start time and end time to create a time window for a schedule. However, the easiest solution – having a user enter the times into two text boxes – seemed clunky and annoying to use. I wanted a better solution that was more intuitive so I decided to try using the jQuery UI Slider for a more visual experience with less typing. My goal was to have a slider with two points to represent the beginning and end of a scheduled time range and to display the value of each point as text.

If you haven’t used jQuery UI before, the slider itself is pretty simple to setup:


<div id="slider-range"></div>
<script type="text/javascript">
	$("#slider-range").slider({
		range: true,
		min: 0,
		max: 1439,
		values: [540, 1020],
		step:5
	});
</script>

View this demo in a new window

This sets a few options for the slider: it is a range between two points, has a value range from 0-1439 (which will later be converted to 12:00 AM to 11:59 PM), and initial values of 9:00 AM (540) and 5:00 PM (1020).

From this point, I needed to read the values from each slider, convert it to a time, and output it to the screen.


<div id="slider-range"></div>
<span id="time"></span>
</script>
<script type="text/javascript">
	$("#slider-range").slider({
		range: true,
		min: 0,
		max: 1439,
		values: [540, 1020],
		slide: slideTime
	});

Here I added a span element to display the time selected using the slider. Then I updated the slider initialization to include instructions on what to do when a slide event fires. A slide event fires for every mouse move during a slide, which is perfect for what I want.


	function slideTime(event, ui){
		var val0 = $("#slider-range").slider("values", 0),
			val1 = $("#slider-range").slider("values", 1),
			minutes0 = parseInt(val0 % 60, 10),
			hours0 = parseInt(val0 / 60 % 24, 10),
			minutes1 = parseInt(val1 % 60, 10),
			hours1 = parseInt(val1 / 60 % 24, 10);
			
		startTime = getTime(hours0, minutes0);
		endTime = getTime(hours1, minutes1);
		$("#time").text(startTime + ' - ' + endTime);
	}

	function getTime(hours, minutes) {
		var time = null;
		minutes = minutes + "";
		if (hours < 12) {
			time = "AM";
		}
		else {
			time = "PM";
		}
		if (hours == 0) {
			hours = 12;
		}
		if (hours > 12) {
			hours = hours - 12;
		}
		if (minutes.length == 1) {
			minutes = "0" + minutes;
		}
		return hours + ":" + minutes + " " + time;
	}
	slideTime();

View this demo in a new window

Next I added two JavaScript functions, *getTime * and slideTime. The function *getTime *grabs the values of each slider point and parses out the hours and minutes using either division or modulo. Those values are then passed to the *getTime *function. *getTime *uses some simple logic to format those times for output including recognizing AM vs PM and correcting minutes without a second digit (9:0 instead of 9:00). After the time is formatted correctly, I use the .text() function to set the value of the #time span element.

This worked great so far, but if I wanted to set a schedule it only allowed me to go in one direction (8:00 PM to 5:00 PM but not 5:00 PM to 8:00 AM). To fix this I doubled the length of the bar, but it also allowed the user to select a window of more than 24 hours. To prevent this from happening, I added a new function: checkMax.


<style>
	#slider-range,#SlideMax{width:400px;}
	#slider-range,#time, #SlideMax, table{margin:10px;display:block;}
</style>
<div id="slider-range"></div>
<span id="SlideMax"></span>
<br />
<span id="time"></span>

<input type="submit" name="scheduleSubmit" value="Submit" id="scheduleSubmit" class="ui-button ui-state-default ui-corner-all"/>
<table id="Schedule">
	<thead>
		<tr>
			<th>Start Time</th>
			<th>End Time</th>
			</tr>
	</thead>
	<tbody>
	</tbody>
</table>

I added a few new html elements here including #SlideMax, which is where the warnings will be displayed and the table #Schedule to display scheduled times, and the button #scheduleSubmit.


	var startTime;
	var endTime;
	$("#slider-range").slider({
		range: true, min: 0, max: 2879, values: [540, 1020], step:5, slide: slideTime, change: checkMax
	});

In the initialization, I changed the range to 0-2879 in order to account for two 24 hour periods, and I added a handler checkMax. Also, to make things a little simpler I added a step option so that the slider will move only in increments of 5 minutes


	function slideTime(event, ui){
		var val0 = $("#slider-range").slider("values", 0),
			val1 = $("#slider-range").slider("values", 1),
			minutes0 = parseInt(val0 % 60, 10),
			hours0 = parseInt(val0 / 60 % 24, 10),
			minutes1 = parseInt(val1 % 60, 10),
			hours1 = parseInt(val1 / 60 % 24, 10);
			
		startTime = getTime(hours0, minutes0);
		endTime = getTime(hours1, minutes1);
		$("#time").text(startTime + ' - ' + endTime);
	}
	function getTime(hours, minutes) {
		var time = null;
		minutes = minutes + "";
		if (hours < 12) {time = "AM";}
		else {	time = "PM";}
		if (hours == 0) {hours = 12;}
		if (hours > 12) {hours = hours - 12;	}
		if (minutes.length == 1) {minutes = "0" + minutes;}
		return hours + ":" + minutes + " " + time;
	}
	function checkMax() {
		var size = $("#slider-range").slider("values", 1) - $("#slider-range").slider("values", 0);
		if( size >= 1435) {
			$("#slider-range div")
				.addClass("ui-state-error")
				.removeClass("ui-widget-header");
			$("#scheduleSubmit")
				.attr("disabled","disabled")
				.addClass("ui-state-disabled")
				.removeClass("ui-state-default");
			$("#SlideMax").text("Cannot be more than 24 hours");
		}
		else {	
			$("#slider-range div")
				.addClass("ui-widget-header")
				.removeClass("ui-state-error");
			$("#scheduleSubmit")
				.removeAttr("disabled")
				.addClass("ui-state-default")
				.removeClass("ui-state-disabled");
			$("#SlideMax").text("");
		}
	}

	$("#scheduleSubmit").on('click', function(){
		console.log(startTime);
		console.log(endTime);
		$('#Schedule tbody').append('<tr>' +
			'<td>' + startTime + '</td>' + 
			'<td>' + endTime + '</td>' + 
			'</tr>');
	});
	slideTime();

View this demo in a new window

At the end I added two more functions, add and checkMax. The function add simply adds a row to that table with the start and end times when the #scheduleSubmit button is clicked. A change event is fired whenever the slider stops moving, and then calls the function checkMax. In checkMax, the two values are subtracted to ensure that they are less than 24 hours apart. If they are too far apart, the #scheduleSubmit button is disabled and a message is displayed in #SlideMax. In addition, the css states are changed on the slider and #scheduleSubmit to let the user know something is different.

So that’s it, a simple solution to use the jQuery UI slider to display time ranges. This can be easily adapted to use for just a single time selection by just removing the “range: true” option from the initialization.

Edit – Continued with  Revisiting the jQuery UI Time Slider