How to Create a Navigable Table with Ajax

Google Maps ( was one of the applications that brought so much attention to Ajax. One of the cool things about it is that it allows the user to drag maps around the screen seamlessly loading new sections. It does this by preloading the sections around the map that the user is likely to drag on to the screen. This same concept can be applied to other applications, such as navigable tables. Learn how to create a navigable table with Ajax in the following steps.

For these examples to work, more files are required than are available in this how to. To see these examples in action, take the Ajax training course.

  1. There are table-specific methods for adding rows and cells. The helper functions shown below makes use of these:
    function addRow(tableId, cells){
    	var tableElem = document.getElementById(tableId);
    	var newRow = tableElem.insertRow(tableElem.rows.length);
    	var newCell;
    	for (var i = 0; i < cells.length; i++) {
    		newCell = newRow.insertCell(newRow.cells.length);
    		newCell.innerHTML = cells[i];
    	return newRow;
  2. Table elements have an insertRow() method, which takes one argument: the position at which to insert the row. The thead, tbody, and tfoot elements also have this method, so our addRow function above can take the id of any of the element types as the first argument. The method inserts an empty row which we then can fill with cells.
  3. Table rows have an insertCell() method. It also takes one argument: the position at which to insert the cell. The inserted cell is empty. Our addRow function above populates the cells from the elements in the passed-in cells array.
  4. We have also created a helper function for deleting rows:
    function deleteRow(tableId, rowNumber){
    	var tableElem = document.getElementById(tableId);
    	if (rowNumber >= 0 && rowNumber < tableElem.rows.length) {
    		return true;
    	} else {
    	return false; //no row to delete
    It uses the deleteRow() method of table, thead, tbody, and tfoot elements to remove the row. If the passed-in rowNumber doesn't exist, the function fails silently by returning false.
  5. The following shows an example of this code in use:
    <meta charset="UTF-8">
    <title>Table Rows</title>
    <link href="TableRows.css" type="text/css" rel="stylesheet">
    <script type="text/javascript" src="lib.js"></script>
    <script type="text/javascript">
    	var tableConfig = {
    		rowsToShow: 2,
    		totalRows: 10 //this number would normally be retrieved from the server
    	function prevRows() {
    		var curRow = Number(document.getElementById("CurRowStart").innerHTML);
    		getRows(curRow - tableConfig.rowsToShow, "prev");
    	function nextRows() {
    		var curRow = Number(document.getElementById("CurRowStart").innerHTML);
    		getRows(curRow + tableConfig.rowsToShow, "next");
    	function getRows(curRow, rowSource) {
    		var slideImage = document.getElementById("CurSlideImage");
    		var curRowStart = document.getElementById("CurRowStart");
    		var curRowEnd = document.getElementById("CurRowEnd");
    		var btnPrev = document.getElementById("PrevButton");
    		var btnNext = document.getElementById("NextButton");
    		var prevTbody = document.getElementById("PrevRows");
    		var nextTbody = document.getElementById("NextRows");
    		var curTbody = document.getElementById("CurRows");
    		var rowsToShow = tableConfig.rowsToShow;
    		var totalRows = tableConfig.totalRows;
    		var xmlhttp;
    		btnPrev.disabled = true;
    		btnNext.disabled = true;
    		if (rowSource == "prev") {
    			for (var i = curTbody.rows.length - 1; i >= 0; i--) {
    				curTbody.replaceChild(prevTbody.rows[i], curTbody.rows[i]);
    				deleteRow("NextRows", i);
    			curRowStart.innerHTML = curRow;
    			curRowEnd.innerHTML = curRow + rowsToShow - 1;
    			message("Loading from Prev");
    		} else if (rowSource == "next") {
    			for (var i = curTbody.rows.length - 1; i >= 0; i--) {
    				curTbody.replaceChild(nextTbody.rows[i], curTbody.rows[i]);
    				deleteRow("PrevRows", i);
    			curRowStart.innerHTML = curRow;
    			curRowEnd.innerHTML = curRow + rowsToShow - 1;
    			message("Loading from Next");
    		url = "TableRows?Row=" + curRow + "&RowsToShow=" + rowsToShow;
    		xmlhttp = new XMLHttpRequest();"get", url, true);
    		xmlhttp.onreadystatechange = function() {
    			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
    		function changeRows(xmlhttp) {
    			var docElem = xmlhttp.responseXML.documentElement;
    			var lastSetStart = totalRows - rowsToShow + 1;
    			var prevRowPos = (curRow == 1) ? null : 0;
    			var curRowPos = (curRow == 1) ? 0 : rowsToShow;
    			var nextRowPos = (curRow == 1) ? rowsToShow :
    				(curRow >= lastSetStart) ? null : 2 * rowsToShow;
    			removeWhitespace(docElem, true);
    			if (prevRowPos !== null) {
    				loadRows("Prev", prevRowPos, docElem);
    				btnPrev.disabled = false;
    			if (nextRowPos !== null) {
    				loadRows("Next", nextRowPos, docElem);
    				btnNext.disabled = false;
    			if (rowSource == "ajax") {
    				loadRows("Cur", curRowPos, docElem);
    				message("Loading from Ajax");
    			curRowStart.innerHTML = curRow;
    			curRowEnd.innerHTML = curRow + rowsToShow - 1;
    	function loadRows(rowset, startRow, docElem) {
    		var endRow = startRow + tableConfig.rowsToShow - 1;
    		var tbodyId = rowset + "Rows";
    		var cells = [],
    			row, cellText;
    		var rowLength = docElem.firstChild.childNodes.length;
    		var htmlRow;
    		for (var i = startRow; i <= endRow; i++) {
    			row = docElem.childNodes[i];
    			for (var j = 0; j < rowLength; j++) {
    				if (row) {
    					cellNode = row.childNodes[j];
    					cellText = cellNode.firstChild.nodeValue;
    					if (cellNode.nodeName == "Image") {
    						cellText = "<img src='Images/" + cellText + "'>";
    				} else {
    					cellText = "";
    			htmlRow = addRow(tbodyId, cells);
    			if (!row) = "none";
    			cells = [];
    	function message(msg) {
    		var output = document.getElementById("Message");
    		output.innerHTML = msg;
    	observeEvent(window, "load", function() {
    		var btnPrev = document.getElementById("PrevButton");
    		var btnNext = document.getElementById("NextButton");
    		var totalRows = tableConfig.totalRows;
    		observeEvent(btnPrev, "click", prevRows);
    		observeEvent(btnNext, "click", nextRows);
    		document.getElementById("TotalRowsNum").innerHTML = totalRows;
    		getRows(1, "ajax");
    <h1>First 10 Presidents</h1>
    <table id="Table">
    	<tbody id="PrevRows"></tbody>
    	<tbody id="CurRows"></tbody>
    	<tbody id="NextRows"></tbody>
    			<td colspan="3">
    				<button id="PrevButton">Previous</button>
    				Rows <span id="CurRowStart">1</span> - <span id="CurRowEnd"></span> of <span id="TotalRowsNum"></span>
    				<button id="NextButton">Next</button>
    			<td colspan="3" id="Message"></td>
    This code renders the following:
    Table Rows
    Note that you must have the associated files to run with this code for it to display correctly.
Author: Chris Minnick

Chris Minnick, the co-founder of WatzThis?, has overseen the development of hundreds of web and mobile projects for customers from small businesses to some of the world’s largest companies. A prolific writer, Chris has authored and co-authored books and articles on a wide range of Internet-related topics including HTML, CSS, mobile apps, e-commerce, e-business, Web design, XML, and application servers. His published books include Adventures in Coding, JavaScript For Kids For Dummies, Writing Computer Code, Coding with JavaScript For Dummies, Beginning HTML5 and CSS3 For Dummies, Webkit For Dummies, CIW E-Commerce Designer Certification Bible, and XHTML.

About Webucator

Webucator provides instructor-led training to students throughout the US and Canada. We have trained over 90,000 students from over 16,000 organizations on technologies such as Microsoft ASP.NET, Microsoft Office, Azure, Windows, Java, Adobe, Python, SQL, JavaScript, Angular and much more. Check out our complete course catalog.