MENU
Teacher was wonderful and class informative!More Testimonials »

More Ajax Applications

In this lesson, you will learn how to build more complex functionality using Ajax.

Lesson Goals

  • Apply the concepts covered thus far to practical applications.
  • Build more complex functionality using Ajax.

Inline Editing

Sometimes it is nice to be able to edit a page without displaying form elements by default. For example, if you want to allow people who are logged in as administrators to edit sections of a page, you could make it so that the administrator could click on those sections to turn them into form elements.

To view the demo, first:

  1. From the command line (on a PC) or terminal (on a Mac), navigate to the directory MoreAjaxApplications/Demos/.
  2. Type npm install to load the required Node.js modules.
  3. Type npm start to start the server.
  4. Open http://localhost:8080/Presidents in a browser to view the page

Our example below shows a simple table showing the presidents' first and last names:

The neat thing about this table is that the names become editable when double clicked:

All the user has to do is type a new value and tab out or click anywhere else in the document to change the value in the table. An XMLHttpRequest is used to change the record in the database.

This page is generated by the Node.js response route /Presidents in MoreAjaxApps/Demos/server.js and rendered by the MoreAjaxApps/Demos/Presidents.jade template. The server-side code queries the "Presidents" database to retrieve a list of all presidents' IDs, first and last names, and bios, and returns those data as an HTML table.

The code queries the database for the presidents' first and last names and biographies (taken from the Whitehouse website) and then iterates through the result set creating a table row for each president. Each td element has the editable class.

The Jade template includes a call to MoreAjaxApps/Demos/inline-editing.js, which does the real work:

Code Sample:

MoreAjaxApps/Demos/inline-editing.js
function enableEditing() {
	var editableElems = getElementsByClassName(document, "editable");
	var numElems = editableElems.length;
	for (var i = 0; i < numElems; i++) {
		observeEvent(editableElems[i], "dblclick", editElem);
	}
}

function editElem(e) {
	var target = getTarget(e);
	var input;
	var textLen = target.innerHTML.length;
	if (textLen > 30) {
		target.innerHTML = "<textarea cols='120' rows='6'>" + target.innerHTML + "</textarea>";
	} else {
		target.innerHTML = "<input value='" + target.innerHTML + "'>";
	}
	var input = target.firstChild;
	input.select();
	observeEvent(input, "blur", saveCell);
}

function saveCell(e) {
	var target = getTarget(e);
	var td = target.parentNode;
	var tr = td.parentNode;
	var field = td.title;
	var value = target.value;
	var pid = tr.id;

	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open("POST", "SaveCell", true);
	xmlhttp.onreadystatechange = function() {
		if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
			td.innerHTML = target.value;
			blinkText(td, 1000, "Saved", "Normal");
		}
	}
	xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
	xmlhttp.send("field=" + field + "&value=" + value + "&pid=" + pid);
}

function blinkText(elem, time, on, off, timePast) {
	var timePast = timePast + 100 || 0;
	if (hasClassName(elem, on)) {
		removeClass(elem, on);
	} else {
		addClass(elem, on);
	}

	if (timePast < time) {
		setTimeout(function() {
			blinkText(elem, time, on, off, timePast)
		}, 100);
	} else {
		removeClass(elem, on);
		removeClass(elem, off);
	}
}

This is the JavaScript library. It has the following functions:

  • enableEditing()
    1. Gets all the elements with the "editable" class using the getElementsByClassName() function from lib.js and attaches the editElem() function to their double-click events.
  • editElem()
    1. Changes the innerHTML of the double-clicked td to an input or textarea tag (depending on the length of the innerHTML) and attaches the saveCell() function to its change event.
  • saveCell()
    1. Uses Ajax to send the field, value and president id to SaveCell.jsp, which updates the record.
    2. The inline callback function changes the innerHTML of the td to the new value and calls blinkText().
  • blinkText()
    1. Toggles the class name of the passed in element (elem) between the passed-in on and off values for timePast milliseconds. This creates a blinking effect.

The contenteditable Attribute

HTML5 includes a contenteditable attribute that can be applied to almost any element, though Internet Explorer does not allow it on elements that make up tables (e.g, table, tr, td, etc.). Editing contenteditable content in the browser can be tricky/quirky when nested tags are involved, but it is pretty simple (and cool) when you are dealing with straight text.

To run the demo, first start the Node.js server if it isn't already running: navigate from the command line/terminal to MoreAjaxApps/Demos/ and type npm start. Then browse to http://localhost:8080/contenteditable.html.

The code is simple:

Code Sample:

MoreAjaxApps/Demos/contenteditable.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Content Editable</title>
</head>
<body>
<p contenteditable="true" style="font-size:xx-large">I am editable.</p>
</body>
</html>

All you have to do to make an element editable is add contenteditable="true" to the tag. The screenshot below shows the page after the user has clicked in the paragraph and entered the word "truly."

Although contenteditable wasn't added to the specification until HTML5, it is well supported by browsers in use today - even Internet Explorer 6.

Of course, when the user changes content on the page that doesn't have any permanent effect. You, as the developer, have to catch that change and do something about it. When a editable element loses focus, a blur event is triggered (there is no change event). You can use the blur event to trigger Ajax code that saves any changes the user made. Run the following example to see how it works:

Code Sample:

MoreAjaxApps/Demos/contenteditable-blur.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Content Editable</title>
<script type="text/javascript" src="lib.js"></script>
<script type="text/javascript">
	observeEvent(window, "load", function() {
		var p1 = document.getElementById("p1");
		observeEvent(p1, "blur", function(e) {
			var target = getTarget(e);
			alert(target.innerHTML);
		});
	});
</script>
</head>
<body>
<p id="p1" style="font-size:xx-large" contenteditable="true">I am editable.</p>
</body>
</html>

Using contenteditable for Inline Editing

Duration: 20 to 30 minutes.

In this exercise, you will improve the inline editing page to make use of the contenteditable attribute instead of form elements.

  1. Navigate to the directory MoreAjaxApps/Exercises/ from the command line. Type npm install to install the needed Node.js modules.
  2. Type npm start from the command line to start the Node.js server.
  3. Open MoreAjaxApps/Exercises/inline-editing.js for editing. This file currently contains the same code we saw in the demo earlier.
  4. Delete the editElem() function. You won't need it.
  5. Modify the enableEditing() function so that the text of the editable elements gets surrounded with a span tag that has the contenteditable attribute set to "true." Attach the saveCell() function to blur events on the new span tag. We no longer need to observe double clicks.
  6. Modify the saveCell() function so that it gets the correct value. Remember, we are now using a span rather than a form element. Also, in the callback function, we no longer need to change the form field back to text.
  7. Test your solution by opening http://localhost:8080/Presidents in your browser and modifying a field. The text should blink. Refresh the page to see if your change stuck.

Solution:

MoreAjaxApps/Solutions/inline-editing.js
function enableEditing() {
	var editableElems = getElementsByClassName(document, "editable");
	var numElems = editableElems.length;
	var elem;
	for (var i = 0; i < numElems; i++) {
		elem = editableElems[i];
		elem.innerHTML = "<span contenteditable='true'>" + elem.innerHTML + "</span>";
		observeEvent(elem.firstChild, "blur", saveCell);
	}
}

function saveCell(e) {
	var target = getTarget(e);
	var td = target.parentNode;
	var tr = td.parentNode;
	var field = td.title;
	var value = target.innerHTML;
	var pid = tr.id;

	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open("POST", "SaveCell", true);
	xmlhttp.onreadystatechange = function() {
		if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
			blinkText(td, 1000, "Saved", "Normal");
		}
	}
	xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
	xmlhttp.send("field=" + field + "&value=" + value + "&pid=" + pid);
}

function blinkText(elem, time, on, off, timePast) {
	var timePast = timePast + 100 || 0;
	elem.className = (elem.className == on) ? off : on;

	if (timePast < time) {
		setTimeout(function() {
			blinkText(elem, time, on, off, timePast)
		}, 100);
	} else {
		elem.className = "editable";
	}
}

observeEvent(window, "load", enableEditing);

The for loop in function enableEditing wraps the inner HTML contents of each element with class editable with a span tag with the attribute contenteditable='true'. The listener observeEvent is attached to each span, fired on the blur event.

The blur event - that is, when the field loses focus - invokes the saveCell function, which sends (via Ajax) the name and value of the changed field to the Node.js SaveCell response route in MoreAjaxApps/Solutions/server.js. The response route, in turn, updates the database.

Detailed Information on Demand

Netflix, the online movie rental company, has a cool feature on their website (http://www.netflix.com) that allows users to hover over a picture of a movie to get more detailed information about that movie. This makes it possible to give users the detailed information they want without downloading detailed information about every movie shown on the page. A screenshot is shown below:

We've done something similar (though not as fancy) with our Presidents page:

Start the Node.js server in the MoreAjaxApps/Demos directory (npm start) and visit http://localhost:8080/TableRowsMoreInfo in your browser.

The JavaScript code is shown below:

Code Sample:

MoreAjaxApps/Demos/more-info.js
function getBio(e) {
	var bioDiv = document.getElementById("Bio");
	var target = getTarget(e);
	var presID = target.parentNode.parentNode.id;
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open("GET", "Bio?id=" + presID, true);
	xmlhttp.onreadystatechange = function() {
		if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
			showBio(xmlhttp);
		}
	}
	xmlhttp.send(null);

	function showBio(xmlhttp) {
		bioDiv.innerHTML = xmlhttp.responseText;
		bioDiv.style.marginTop = (presID * 54) + "px"; //position element (hack)
		bioDiv.style.visibility = "visible";
	}
}

function hideBio() {
	var bioDiv = document.getElementById("Bio");
	bioDiv.style.visibility = "hidden";
	bioDiv.innerHTML = "";
}

observeEvent(window, "load", function() {
	var table = document.getElementById("Table");
	var imgs = table.getElementsByTagName("img");
	var numImages = imgs.length;
	for (var i = 0; i < numImages; i++) {
		observeEvent(imgs[i], "mouseover", getBio);
		observeEvent(imgs[i], "mouseout", hideBio);
	}
});

The TableRowsMoreInfo response route in MoreAjaxApps/Demos/server.js generates, and MoreAjaxApps/Demos/TableRowsMoreInfo.jade renders, the presidents HTML table and includes the more-info.js file. When the page loads, we attach mouseover and mouseout events to the images to call showBio() and hideBio(), respectively. The getBio() function calls the Bio response route, passing along the ID of the moused-over president, and gets the biography of the associated president as a response. Its nested showBio() callback function displays the biography.

When the user mouses out, hideBio() hides the div containing biography.

Autologout

If a user is idle for a certain amount of time, it is often a good idea to force a logout, especially if there might be sensitive data on the screen. This is normally handled on the server side; however, if we want to hide the data on the screen and alert the user that the session has ended, we'll need to handle the session on the client as well. One way to handle this is described below:

  1. When the user logs in, create a JavaScript timer with the window.setTimeout() method. The timer will call a function that ends the session after n minutes.
  2. Whenever there is user activity, the timer must be restarted.
  3. When the user explicitly logs out (e.g, clicks on a logout button), the timer must be killed.

Start the Node.js server by typing npm start from the command line in the directory MoreAjaxApps/Demos/. Open http://localhost:8080/PresidentsLogin.html in a browser to view the working example.

To illustrate, we will be forcing the presidents to login to our inline editing application. The logins are all first initial - lastname (e.g, "gwashington") and the passwords are all the word "password". First, let's look at the application. It starts with a simple login form:

When the user logs in, the editable table appears. We also provide a Logout button, so the user can log himself out:

When the session times out, the page goes blank and an alert appears informing the user that the session has timed out:

After the user clicks on the OK button, the login form reappears. Let's look at the code. There are quite a few files involved. The main file is shown below:

Code Sample:

MoreAjaxApps/Demos/PresidentsLogin.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Authentication</title>
<link href="Presidents.css" type="text/css" rel="stylesheet">
<link href="Login.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="lib.js"></script>
<script type="text/javascript" src="inline-editing.js"></script>
<script type="text/javascript">
	var presConfig = {
		userName: null,
		autoLogoutTimer: null
	}

	function startApp() {
		var loggedInDiv = document.getElementById("LoggedInDiv");
		var logOutDiv = document.getElementById("LogoutDiv");
		loggedInDiv.innerHTML = "Logged in as " + presConfig.userName;
		loggedInDiv.style.display = "block";
		logOutDiv.style.display = "block";
		showPresidents();
		startAutoLogoutTimer();
		observeEvent(document.body, "click", startAutoLogoutTimer);
	}

	function endApp() {
		var loggedInDiv = document.getElementById("LoggedInDiv");
		var logOutDiv = document.getElementById("LogoutDiv");
		clearTimeout(presConfig.autoLogoutTimer);
		presConfig.userName = null;
		loggedInDiv.innerHTML = "";
		loggedInDiv.style.display = "none";
		logOutDiv.style.display = "none";
		loginForm();
		unObserveEvent(document.body, "click", startAutoLogoutTimer);
	}

	function showPresidents() {
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.open("GET", "Controller?req=Table", true);
		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				results(xmlhttp);
			}
		}
		xmlhttp.send(null);

		function results(xmlhttp) {
			var output = document.getElementById("Output");
			output.innerHTML = xmlhttp.responseText;
			enableEditing();
		}
	}

	function loginForm() {
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.open("GET", "Controller?req=LoginForm", true);
		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				results(xmlhttp);
			}
		}
		xmlhttp.send(null);

		function results(xmlhttp) {
			var output = document.getElementById("Output");
			var loginForm;
			output.innerHTML = xmlhttp.responseText;
			loginForm = document.getElementById("LoginForm");
			loginForm.onsubmit = function() {
				login(loginForm.Username.value, loginForm.Password.value);
				return false;
			}
		}
	}

	function login(un, pw) {
		var params = "username=" + un + "&password=" + pw;
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.open("POST", "Controller?req=Login", true);
		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				results(xmlhttp);
			}
		}
		xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
		xmlhttp.send(params);

		function results(xmlhttp) {
			if (xmlhttp.responseText.indexOf("failed") == -1) {
				presConfig.userName = xmlhttp.responseText;
				startApp();
			} else {
				var badLogin = document.getElementById("BadLogin");
				var userName = document.getElementById("Username");
				badLogin.style.display = "block";
				userName.select();
				userName.className = "Highlighted";
				setTimeout(function() {
					document.getElementById('BadLogin').style.display = 'none';
				}, 5000);
			}
		}
	}

	function startAutoLogoutTimer() {
		var sessionTime = 15 * 1000; //15 seconds
		clearTimeout(presConfig.autoLogoutTimer);
		presConfig.autoLogoutTimer = setTimeout(function() {
			logout(true);
		}, sessionTime);
	}


	function logout(auto) {
		var xmlhttp = new XMLHttpRequest();
		document.getElementById("Output").innerHTML = "";
		xmlhttp.open("GET", "Controller?req=Logout", true);
		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				results(xmlhttp);
			}
		}
		xmlhttp.send(null);

		function results(xmlhttp) {
			endApp();
			if (auto) {
				alert("You have been logged out due to inactivity.");
			}
		}
	}

	function checkLogin() {
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.open("GET", "Controller?req=LoggedIn", true);
		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				results(xmlhttp);
			}
		}
		xmlhttp.send(null);

		function results(xmlhttp) {
			if (xmlhttp.responseText.indexOf("failed") == -1) {
				presConfig.userName = xmlhttp.responseText;
				startApp();
			} else {
				loginForm();
			}
		}
	}

	observeEvent(window, "load", function() {
		var btnLogout = document.getElementById("logout");
		observeEvent(btnLogout, "click", function() {
			logout(false);
		});
		checkLogin();
	});
</script>
</head>
<body>
<div id="LogoutDiv">
	<button id="logout">Logout</button>
</div>
<div id="LoggedInDiv"></div>
<div id="Output">One moment please...</div>
</body>
</html>

This page contains the basic HTML elements that will hold data returned from the server:

<div id="LogoutDiv"> <button id="logout">Logout</button> </div> <div id="LoggedInDiv"></div> <div id="Output">One moment please...</div>

The "Output" div will hold the login form or the table data, depending on whether or not the user is logged in. This page also controls the flow of the application:

When the page loads, the checkLogin() function is called, which looks like this:

function checkLogin() { var xmlhttp = new XMLHttpRequest(); xmlhttp.open("GET","Controller?req=LoggedIn",true); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { results(xmlhttp); } } xmlhttp.send(null); function results(xmlhttp) { if (xmlhttp.responseText.indexOf("failed") == -1) { presConfig.userName = xmlhttp.responseText; startApp(); } else { loginForm(); } } }

It makes an Ajax request to Controller, which handles the assignment of tasks based on the req parameter. In this case, the server-side code checks to see if the user is logged in: if so, it returns the user's name; if not, it returns the text "failed" if s/he is not logged in. The results() callback function then calls startApp() (if the user is logged in) to start the application or loginForm() (if the user is NOT logged in) to show the login form. Let's first see what happens when the user is NOT logged in:

function loginForm() { var xmlhttp = new XMLHttpRequest(); xmlhttp.open("GET","Controller?req=LoginForm",true); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { results(xmlhttp); } } xmlhttp.send(null); function results(xmlhttp) { var output = document.getElementById("Output"); var loginForm; output.innerHTML = xmlhttp.responseText; loginForm = document.getElementById("LoginForm"); observeEvent(loginForm,"submit",function() { login(loginForm.Username.value,loginForm.Password.value); return false; }); } }

The loginForm() function uses Ajax to get an HTML login form and then, in the results() callback function displays the form and attaches the login() function to its submit event.

When the user logs in, the login() function is called:

function login(un,pw) { var params="username=" + un + "&password=" + pw; var xmlhttp = new XMLHttpRequest(); xmlhttp.open("POST","Controller?req=Login",true); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { results(xmlhttp); } } xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8"); xmlhttp.send(params); function results(xmlhttp) { if (xmlhttp.responseText.indexOf("failed") == -1) { presConfig.userName = xmlhttp.responseText; startApp(); } else { var badLogin = document.getElementById("BadLogin"); var userName = document.getElementById("Username"); badLogin.style.display="block"; userName.select(); userName.className="Highlighted"; setTimeout(function() {document.getElementById('BadLogin').style.display='none'; },5000); } } }

The login() function sends the passed-in username and password to the Controller response route using Ajax to try to log the user in. If the login succeeds, the server returns the user's full name (e.g, George Washington). If the login fails, the server returns "failed". The results() callback function either starts the application or displays a bad-login message and leaves the form in place for the user to try again.

When the user does successfully log in, the startApp() function is called:

function startApp() { var loggedInDiv = document.getElementById("LoggedInDiv"); var logOutDiv = document.getElementById("LogoutDiv"); loggedInDiv.innerHTML = "Logged in as " + presConfig.userName; loggedInDiv.style.display="block"; logOutDiv.style.display="block"; showPresidents(); startAutoLogoutTimer(); observeEvent(document.body,"click",startAutoLogoutTimer); }

The startApp() function does the following:

  1. Shows the logged-in message and the Logout button.
  2. Calls showPresidents(), which gets the editable Presidents table we saw in earlier demos.
  3. Calls startAutoLogoutTimer(), which starts the inactivity timer. This function is recalled every time the user clicks the mouse. It is shown below:
function startAutoLogoutTimer() { var sessionTime = 15 * 1000; //15 seconds clearTimeout(presConfig.autoLogoutTimer); presConfig.autoLogoutTimer = setTimeout(function() { logout(true); }, sessionTime); }

The startAutoLogoutTimer() function simply sets a timer to call logout() after 15 seconds and passing in true to indicate that it is an auto logout vs. a user-initiated logout. The function is recalled (and the timer restarted) each time the user clicks the mouse. We set the timer at 15 seconds so that you wouldn't have to wait too long to see it work. Normally, it would be much longer. The logout() function is shown below:

function logout(auto) { var xmlhttp = new XMLHttpRequest(); var loggedInDiv = document.getElementById("LoggedInDiv"); var logOutDiv = document.getElementById("LogoutDiv"); var output = document.getElementById("Output"); xmlhttp.open("HEAD","Controller?req=Logout",true); xmlhttp.send(null); clearTimeout(presConfig.autoLogoutTimer); output.innerHTML = ""; loggedInDiv.innerHTML = ""; loggedInDiv.style.display="none"; logOutDiv.style.display="none"; loginForm(); unObserveEvent(document.body,"click",startAutoLogoutTimer); if (auto) { alert("You have been logged out due to inactivity."); } }

As we don't need a response from the server to log the user out, we use the "HEAD" method to send the request. The rest of the function sets the page back as it was when it first loaded.

Autocompletion

Developers have become very excited about "autocomplete" dropdowns since Google began using it some years ago. A screenshot is shown below:

Writing your own autocompletion scripts would be a difficult undertaking. And it's unlikely to be worth your while, as there are many such scripts available for free. We will use the Autocomplete widget provided as part of the jQuery UI library. jQuery UI is an interface library - offering a set of interactions, widgets, effects, and utilities - built on top of (and requiring the use of) the jQuery library. You can learn more about jQuery UI at http://jqueryui.com/, and more about jQuery UI Autocomplete at http://jqueryui.com/autocomplete/

To use jQuery UI, we must first include the jQuery library via a script tag, and then include the jQuery UI library, via a script tag as well.

As with jQuery, we can reference jQuery UI either directly - by downloading the library to our local server - or via a content delivery network (CDN). We have downloaded both jQuery and jQuery UI in this case.

Usually, we also include several stylesheets along with the jQuery UI JavaScript library; these stylesheets (one for the basic structure of jQuery UI widgets and elements, and one for the visual design of the elements) can also be downloaded or referenced from a CDN. We have, as with the JavaScript libraries, downloaded the files to our server.

The code is shown below:

Code Sample:

MoreAjaxApps/Demos/AutoComplete.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>AutoComplete</title>
<link rel="stylesheet" type="text/css" href="AutoComplete.css">
<link rel="stylesheet" type="text/css" href="jquery-ui.structure.min.css">
<link rel="stylesheet" type="text/css" href="jquery-ui.theme.min.css">
<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="jquery-ui.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		$("#President").autocomplete({
			source: "AutoComplete",
			minLength: 2,
			select: function(event, ui) {
				alert("Selected: " + ui.item.value + " with ID#" + ui.item.id);
			}
		});
	});
</script>
</head>
<body>
<form>
	<input type="text" size="40" name="President" id="President">
</form>
</body>
</html>

After including the needed CSS and JavaScript files, we use jQuery's ready method to attach an autocomplete to the <div> with id President.

The source attribute specifies the remote data source: the AutoComplete response route defined in MoreAjaxApps/Demos/server.js. The route accepts a request parameter term - the value typed by the user.

The AutoComplete response route queries the database:

"SELECT PresidentID as id, FirstName || ' ' || LastName as value FROM Presidents WHERE FirstName LIKE '%" + President + "%' OR LastName LIKE '%" + President + "%'";

The double pipes (||) are concatenation in SQLite (the type of database we use here), building a fullname (and returning it as the computed field value) for any president whose first or last name matches the user's text.

Many JavaScript frameworks, including jQuery, YUI and GWT, provide similar built-in autocompleters.

CORS/JSONP → ← Ajax Applications

Client Success
  1. Compare Us
  2. Client List
  3. Testimonials
Join The Team
  1. Learn how you can become a Webucator Trainer
  2. Career Opportunities
Locations
© Webucator, Inc. All rights reserved. |Toll Free: 1-877-932-8228Toll Free: 1-877-932-8228 |Outside the USA: 315-849-2724|Fax: 315-849-2723