2012
07.12

When displaying sets of records on the web it’s a very common thing to include a checkbox on each row to allow users to select rows for things like, deleting multiple records, moving records from one place to another or whatever your case may be. It’s pretty standard and a nice addition to add a single checkbox in the header to allow users to select all the rows with one click – and then you add pagination and the user experience falls apart. I had a user ask me, “When I click the ‘select all’ checkbox, are all the rows selected, or just the ones on this page?”.
Clearly I needed to be a bit more specific. Here’s the solution that was used.

I swapped out the header checkbox with the following set of 3 checkboxes and bits of HTML.

<div id="moreOptsParent">
	<input title="Check all records" id="checkAllDisplay" type="checkbox">
	<div id="moreOptsPanel" style="display:none; position:absolute; background-color:#a6d9f4; padding:5px; text-align:left;">
		<input title="Check all records on current page" 
			id="checkAllRecords" type="checkbox"> 
				All records on current page <br />
		<input title="Check all records on all pages" 
			id="checkAllPages" type="checkbox"> 
				All records on all pages
	</div>
<div>

The above HTML leaves one checkbox in the header and two more in a hidden div. The one that’s visible will be used to indicate some kind of selection, and the other two will be shown and hidden with jQuery to allow two choice options.

  • All records on current page
  • All records on all pages

The first part to be handled is the showing and hiding of the checkboxes. Using a timer, I added a delay to the ‘hide’ function so that it’s less jumpy and moving your mouse outside the element by accident won’t hide it and frustrate my users. While it’s not required, notice that I named my anonymous functions with something that helps clarify their purpose, “enterElement” and “exitElement”.

var moreOptsTimer;
$("#moreOptsParent").hover(function enterElement() {
		clearTimeout(moreOptsTimer);
		$("#moreOptsPanel").show().animate({ height: 40 }, 
						{ duration: "slow" });
	},
	function exitElement() {
		moreOptsTimer = setTimeout(function () {
			$("#moreOptsPanel").animate({ height: 0 }, 
			{ duration: "slow" }, 
			function () {
				// Animation complete.
				$("#moreOptsPanel").hide();
			});
		}, 500);
	}
);

Now that the two selection choices hide and show nicely we have to add code to manage the state of the checkboxes to show selections. When we select “all rows current page”, we need to check the header checkbox and the one on each row. When we select “all rows on all pages”, we need to check the header checkbox and uncheck & disable the one on each row. For completeness I’ve mirrored the “All Records current page” function on the original checkbox but because the behaviour is so slightly different, it gets it’s own click function.

	/* attach event handler to "check all" checkbox */
	$('#checkAllDisplay').click(function () {
		$("#MyGridItems tbody input:checkbox").removeAttr("disabled")
						.attr("checked", this.checked);
		$('#checkAllRecords').attr("checked", this.checked);
		if (!this.checked) {
			$('#checkAllPages').attr("checked", false);
		}
	});

	/* attach event handler to "check all on current page" checkbox */
	$('#checkAllRecords').click(function () {
		$("#MyGridItems tbody input:checkbox").removeAttr("disabled")
					.attr("checked", this.checked);
		$('#checkAllDisplay').attr("checked", this.checked);
		if (this.checked) {
			$('#checkAllPages').attr("checked", false);
		}
	});

	/* attach event handler to "check all on all pages" checkbox */
	$('#checkAllPages').click(function () {
		$('#checkAllDisplay').attr("checked", this.checked);
		if (this.checked) {
			$('#checkAllRecords').attr("checked", false);
			$("#MyGridItems tbody input:checkbox")
							.attr("disabled", true)
							.attr("checked", false);
		} else {
			$("#MyGridItems tbody input:checkbox")
							.removeAttr("disabled");
		}
	});

Try the demo and leave a comment below if you found it useful or had a suggestion.

Comments are closed.