You are on page 1of 24

Login Form

Have you ever forgotten your username or password for a website? Have you waited 10 seconds for a full page to redraw while the only thing new is a message telling you that the username and password are not recognized. Ajax can make that process much less painful for the user. Imagine a simple login form like the one shown below, but on a page with a lot of other content:

When the user fills the form out with a bad password, an error message appears and the

username is highlighted: The rest of the page should stay the same. Ajax makes this possible without refreshing the entire page. The code for this is shown below:

Code Sample: AjaxApplications/Demos/Login.html


<html> <head> <title>Login Form</title> <link href="Login.css" type="text/css" rel="stylesheet"/> <script type="text/javascript" src="../../prototype.js"></script> <script type="text/javascript"> function Login(FORM) { var un = FORM.Username.value; var pw = FORM.Password.value; new Ajax.Request("Login.jsp", { method: "get",

parameters: "username=" + un + "&password=" + pw, onComplete: LoginResults });

function LoginResults(REQ) //Callback Function { if (REQ.responseText.indexOf("failed") == -1) { document.getElementById("LoggedIn").innerHTML = "Logged in as " + REQ.responseText; document.getElementById("LoggedIn").style.display = "block"; document.getElementById("LoginForm").style.display = "none"; } else { document.getElementById("BadLogin").style.display="block"; document.getElementById("LoginForm").Username.select(); document.getElementById("LoginForm").Username.className="Highlighted"; setTimeout( function() { document.getElementById('BadLogin').style.display='none'; },3000); } } </script> </head> <body> <form id="LoginForm" onsubmit="Login(this); return false"> <h1>Login Form</h1> <div class="FormRow"> <label for="Username">Username:</label> <input type="text" size="15" id="Username" name="Username"/> </div> <div class="FormRow"> <label for="Password">Password:</label> <input type="password" size="15" id="Password" name="Password"/> </div> <div class="FormRow" id="LoginButtonDiv"> <input type="submit" value="Login"/> </div> <div id="BadLogin"> The login information you entered does not match an account in our records. Please try again. </div> </form> <h1 id="LoggedIn"></h1> </body> </html>

Quick Lookup Form

In some cases, you need to get quick information from a database, but you don't want to process an entire page. For example, you may have a form for requesting information about an order. The form might have multiple fields, one of which is the order id. The order id is not required, but if it's filled in it must match an existing order id in the database. Rather than waiting to check the order id until the user fills out and submits the entire form, you can use Ajax to flag a bad order id as soon as the user tabs out of that field. A simple sample interface is shown below:

When the user enters an order id that is not in the database, an error is displayed and the submit

button becomes disabled:

When the user enters a valid order id, an icon is displayed indicating that the order id exists and the submit button becomes enabled:

The code is shown below.

Code Sample: AjaxApplications/Demos/Lookup.html


<html> <head> <title>Order Lookup Form</title> <link href="Lookup.css" type="text/css" rel="stylesheet"/> <script type="text/javascript" src="../../prototype.js"></script> <script type="text/javascript"> function Lookup(ORDER) { var orderNum = ORDER.value; if (orderNum.length==0) //OK to submit { document.getElementById("OrderNumError").innerHTML=""; document.getElementById("SubmitButton").disabled=false; return true; } if (isNaN(orderNum)) //Error { document.getElementById("OrderNumError").innerHTML="Must be numeric."; ORDER.style.color="red"; document.getElementById("SubmitButton").disabled=true; return true;

} //Look up order number in database new Ajax.Request("Lookup.jsp", { method: "get", parameters: "orderNum=" + orderNum, onComplete: LookupResults });

function LookupResults(REQ) //Callback function { if (REQ.responseText.indexOf("success") == -1) //Error: no match { document.getElementById("OrderNumError").innerHTML="No such order number."; document.getElementById("OrderNum").style.color="red"; document.getElementById("SubmitButton").disabled=true; } else //OK to submit { document.getElementById("OrderNumError").innerHTML="<img src='check.gif'/>"; document.getElementById("OrderNum").style.color="green"; document.getElementById("SubmitButton").disabled=false; } } </script> </head> <body> <form id="LookupForm" onsubmit="alert('Form would submit.'); return false;"> <h1>Lookup Form</h1> <p>Enter an order number.</p> <div class="FormRow"> <label for="OrderNum">Order Number:</label> <input type="text" size="10" id="OrderNum" name="OrderNum" onblur="Lookup(this)"/> <span id="OrderNumError"></span> </div> <div class="FormRow"> <label for="Comments">Comments:</label><br /> <textarea id="Comments" name="Comments" cols="40" rows="4"></textarea> </div> <div class="FormRow"> <input type="submit" id="SubmitButton" value="Submit"/> </div> </form> </body> </html>

Code Sample: AjaxApplications/Demos/Lookup.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" import="java.sql.*"%> <% Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); conn = DriverManager.getConnection("jdbc:odbc:Northwind"); String sql = "SELECT OrderID From Orders WHERE OrderID=?"; stmt = conn.prepareStatement(sql); stmt.setString(1, request.getParameter("orderNum")); rs = stmt.executeQuery(); if (rs.next()) { out.write("success"); } else { out.write("failed"); } } catch(Exception e) { out.write("failed: " + e.toString()); } finally { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } %>

Code Explanation The server-side script simply return "success" if the order number is found or "failed" if it is not.

Exercise: Creating a Simple Lookup Form


Duration: 20 to 30 minutes.

In this exercise, you will create a lookup form that takes a year and returns the name of the person who was president that year. The page looks like this:

1. Open AjaxApplications/Exercises/Lookup.jsp in your editor. This page is complete. It

expects a year to be passed in and returns an HTML string containing the names of the presidents who were in office that year. 2. Open AjaxApplications/Exercises/Lookup.html in your editor. o Modify the Lookup() function so that it uses prototype to make a call to Lookup.jsp and passes in the year as "year" using the get method. The callback function should be LookupResults(). o Write the LookupResults() callback function. It should write out the code returned from the server to the "LookupResults" div. 3. Test your solution by opening AjaxApplications/Exercises/Lookup.html in the browser. You'll do your work here:

Code Sample: AjaxApplications/Exercises/Lookup.html


<html> <head> <title>Lookup Form</title> <link href="Lookup.css" type="text/css" rel="stylesheet"/> <script type="text/javascript" src="../../prototype.js"></script> <script type="text/javascript"> function Lookup(FORM) { var year = FORM.Year.value; if (isNaN(year) || year.length != 4) {

alert("Please enter a valid year."); return false; } /* Use prototype to make a call to Lookup.jsp and pass in the year as "year" using the get method. The callback function should be LookupResults. */ } /* Write the LookupResults() callback function. It should write out the code returned from the server to the "LookupResults" div. */ </script> </head> <body> <form id="LookupForm" onsubmit="Lookup(this); return false;"> <h1>Lookup Form</h1> <p>Enter a year between 1789 and 1845 to find out who was president that year.</p> <div class="FormRow"> <label for="Year">Year:</label> <input type="text" size="5" id="Year" name="Year"/> <input type="submit" value="Lookup"/> </div> <hr/> <div class="FormRow" id="LookupResults"></div> </form> </body> </html>

The server-side script is complete.

Code Sample: AjaxApplications/Exercises/Lookup.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" import="java.sql.*"%> <% Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); conn = DriverManager.getConnection("jdbc:odbc:Presidents"); String sql = "SELECT FirstName, LastName, StartYear, EndYear FROM Presidents WHERE StartYear <= ? AND EndYear >= ?"; stmt = conn.prepareStatement(sql); stmt.setString(1, request.getParameter("year")); stmt.setString(2, request.getParameter("year"));

rs = stmt.executeQuery(); int i = 0; while (rs.next()) { out.write(rs.getString("FirstName") + " " + rs.getString("LastName")); out.write(" (" + rs.getString("StartYear") + " - " + rs.getString("EndYear") + ")<br/>"); i++; } if (i==0) { out.write("No results"); } } catch(Exception e) { out.write("failed: " + e.toString()); } finally { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } %>

Where is the solution?

Preloaded Data
Google Maps (http://maps.google.com) 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 slideshows and navigable tables.

Ajax Slideshow

Let's first take a look at the slideshow shown below:

When the user clicks on the Previous or Next buttons, the page makes an XMLHttpRequest to

the server, which returns XML as shown below: The callback function creates the next slide from this XML. The code is shown below.

Code Sample: AjaxApplications/Demos/SlideShow.html


<html> <head> <title>Slide Show</title> <link href="SlideShow.css" type="text/css" rel="stylesheet"/> <script type="text/javascript" src="../../prototype.js"></script> <script type="text/javascript"> var CurSlide=1; //Keeps track of current slide var NumSlides = 10; function init() { document.getElementById("PrevButton").onclick=PrevSlide; document.getElementById("NextButton").onclick=NextSlide; document.getElementById("TotalSlideNum").innerHTML = NumSlides;

GetSlide();

function PrevSlide() { if (CurSlide > 1) { CurSlide--; GetSlide(); } else { document.getElementById("SlideMessage").innerHTML = "Already showing first slide."; setTimeout("document.getElementById('SlideMessage').innerHTML=''",2000); } } function NextSlide() { if (CurSlide < NumSlides) { CurSlide++; GetSlide(); } else { document.getElementById("SlideMessage").innerHTML = "Already showing last slide."; setTimeout("document.getElementById('SlideMessage').innerHTML=''",2000); } } function GetSlide() { document.getElementById("CurSlideNum").innerHTML=CurSlide; new Ajax.Request("SlideShow.jsp", { method: "get", parameters: "Slide=" + CurSlide, onComplete: ChangeSlide });

function ChangeSlide(REQ) //Callback function creates slide { var docElem = REQ.responseXML.documentElement; try { Element.cleanWhitespace(docElem); //doesn't work and is unnecessary in IE } catch (e) { //alert(e.message); } document.getElementById("SlideText").innerHTML = docElem.firstChild.firstChild.nodeValue + "<br/>"; document.getElementById("SlideText").innerHTML += docElem.childNodes[1].firstChild.nodeValue;

document.getElementById("SlideImage").src = "Slides/" + docElem.childNodes[2].firstChild.nodeValue; } window.onload = init; </script> </head> <body> <h1>First 10 Presidents</h1> <div id="Slide"> <img id="SlideImage"/> <div id="SlideText"></div> <form action="SlideShow.html" onsubmit="return false" id="SlideForm"> <input type="button" value="Previous" id="PrevButton"/> Slide <span id="CurSlideNum">1</span> of <span id="TotalSlideNum"></span> <input type="button" value="Next" id="NextButton"/> </form> <div id="SlideMessage"></div> </div> </body> </html>

Although this is pretty cool in and of itself, it can be made cooler by preloading the preceding and following images, so the user experiences no delay when navigating from slide to slide. In this case, the server-side script needs to return more data. Our script is shown below.

Code Sample: AjaxApplications/Demos/SlideShowpreloaded.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" import="java.sql.*"%> <% Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); conn = DriverManager.getConnection("jdbc:odbc:Presidents"); String sql = "SELECT FirstName, LastName, StartYear, EndYear, ImagePath FROM Presidents WHERE PresidentID BETWEEN ?-1 AND ?+1"; stmt = conn.prepareStatement(sql); stmt.setString(1, request.getParameter("Slide")); stmt.setString(2, request.getParameter("Slide")); rs = stmt.executeQuery(); response.setContentType("text/xml"); out.write("<Presidents>"); while (rs.next()) {

out.write("<President>"); out.write("<Name>" + rs.getString("FirstName") + " " + rs.getString("LastName") + "</Name>"); out.write("<Years>" + rs.getString("StartYear") + "-" + rs.getString("EndYear") + "</Years>"); out.write("<Image>" + rs.getString("ImagePath") + "</Image>"); out.write("</President>"); } out.write("</Presidents>"); } catch(Exception e) { out.write("failed: " + e.toString()); } finally { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } %>

Code Explanation Notice that the SQL query will return records for the chosen president, the preceding president, and the following president. The resulting XML will look something like this:

Now we need to change the callback function to handle the preloaded slides and change the HTML to have hidden locations for the preloaded data. The code below shows how this is done.

Code Sample: AjaxApplications/Demos/SlideShowpreloaded.html


<html> <head> <title>Slide Show</title> <link href="SlideShow.css" type="text/css" rel="stylesheet"/> <script type="text/javascript" src="../../prototype.js"></script> <script type="text/javascript"> var var var var var CurSlide=1; NumSlides = 10; PrevSlideReady = false; NextSlideReady = false; CurSlideLoaded = false;

function init() { document.getElementById("PrevButton").onclick=PrevSlide; document.getElementById("NextButton").onclick=NextSlide; document.getElementById("TotalSlideNum").innerHTML = NumSlides; GetSlide(); } function PrevSlide() { if (CurSlide > 1) { CurSlide--; if (PrevSlideReady) //use data from PrevSlide placeholder { var slideText = document.getElementById("SlideText"); var prevSlideText = document.getElementById("PrevSlideText"); var slideImage = document.getElementById("SlideImage"); var prevSlideImage = document.getElementById("PrevSlideImage"); slideText.innerHTML = prevSlideText.innerHTML; slideImage.src = prevSlideImage.src; //document.getElementById("SlideMessage").innerHTML = "Loaded from PrevSlide."; PrevSlideReady=false; CurSlideLoaded=true; } GetSlide(); } else { document.getElementById("SlideMessage").innerHTML = "Already showing first slide."; setTimeout("document.getElementById('SlideMessage').innerHTML=''",2000); } } function NextSlide() { if (CurSlide < NumSlides)

CurSlide++; if (NextSlideReady) //Use data from NextSlide placeholder { var slideText = document.getElementById("SlideText"); var nextSlideText = document.getElementById("NextSlideText"); var slideImage = document.getElementById("SlideImage"); var nextSlideImage = document.getElementById("NextSlideImage"); slideText.innerHTML = nextSlideText.innerHTML; slideImage.src = nextSlideImage.src; //document.getElementById("SlideMessage").innerHTML = "Loaded from NextSlide."; NextSlideReady=false; CurSlideLoaded=true; } GetSlide(); } else { document.getElementById("SlideMessage").innerHTML = "Already showing last slide."; setTimeout("document.getElementById('SlideMessage').innerHTML=''",2000); } } function GetSlide() { document.getElementById("CurSlideNum").innerHTML=CurSlide; new Ajax.Request("SlideShow-preloaded.jsp", { method: "get", parameters: "Slide=" + CurSlide, onComplete: ChangeSlide });

function ChangeSlide(REQ) { var docElem = REQ.responseXML.documentElement; var PrevSlideNode, CurSlideNode, NextSlideNode; if (CurSlide == 1) //First slide { PrevSlideNode = null; CurSlideNode = docElem.childNodes[0]; NextSlideNode = docElem.childNodes[1]; try { Element.cleanWhitespace(CurSlideNode); //doesn't work and is unnecessary in IE Element.cleanWhitespace(NextSlideNode); //doesn't work and is unnecessary in IE } catch (e) { //alert(e.message); } PrevSlideReady=false; NextSlideReady=true; }

else if (CurSlide == NumSlides) //Last slide { PrevSlideNode = docElem.childNodes[0]; CurSlideNode = docElem.childNodes[1]; try { Element.cleanWhitespace(PrevSlideNode); //doesn't work and is unnecessary in IE Element.cleanWhitespace(CurSlideNode); //doesn't work and is unnecessary in IE } catch (e) { //alert(e.message); } NextSlideNode = null; PrevSlideReady=true; NextSlideReady=false; } else { PrevSlideNode = docElem.childNodes[0]; CurSlideNode = docElem.childNodes[1]; NextSlideNode = docElem.childNodes[2]; try { Element.cleanWhitespace(PrevSlideNode); //doesn't work and is unnecessary in IE Element.cleanWhitespace(CurSlideNode); //doesn't work and is unnecessary in IE Element.cleanWhitespace(NextSlideNode); //doesn't work and is unnecessary in IE } catch (e) { //alert(e.message); } PrevSlideReady=true; NextSlideReady=true; } if (!CurSlideLoaded) //Use data returned from server { document.getElementById("SlideText").innerHTML = CurSlideNode.childNodes[0].firstChild.nodeValue + "<br/>"; document.getElementById("SlideText").innerHTML += CurSlideNode.childNodes[1].firstChild.nodeValue; document.getElementById("SlideImage").src = "Slides/" + CurSlideNode.childNodes[2].firstChild.nodeValue; } if (PrevSlideNode) { document.getElementById("PrevSlideText").innerHTML = PrevSlideNode.childNodes[0].firstChild.nodeValue + "<br/>"; document.getElementById("PrevSlideText").innerHTML += PrevSlideNode.childNodes[1].firstChild.nodeValue; document.getElementById("PrevSlideImage").src = "Slides/" + PrevSlideNode.childNodes[2].firstChild.nodeValue; } if (NextSlideNode) {

document.getElementById("NextSlideText").innerHTML = NextSlideNode.childNodes[0].firstChild.nodeValue + "<br/>"; document.getElementById("NextSlideText").innerHTML += NextSlideNode.childNodes[1].firstChild.nodeValue; document.getElementById("NextSlideImage").src = "Slides/" + NextSlideNode.childNodes[2].firstChild.nodeValue; } CurSlideLoaded=false; } window.onload = init; </script> </head> <body> <h1>First 10 Presidents</h1> <div id="PrevSlide"> <img id="PrevSlideImage"/> <div id="PrevSlideText"></div> </div> <div id="Slide"> <img id="SlideImage"/> <div id="SlideText"></div> <form action="SlideShow.html" onsubmit="return false" id="SlideForm"> <input type="button" value="Previous" id="PrevButton"/> Slide <span id="CurSlideNum">1</span> of <span id="TotalSlideNum"></span> <input type="button" value="Next" id="NextButton"/> </form> <div id="SlideMessage"></div> </div> <div id="NextSlide"> <img id="NextSlideImage"/> <div id="NextSlideText"></div> </div> </body> </html>

Code Explanation Notice these two divs in the HTML body:


<div id="PrevSlide"> <img id="PrevSlideImage"/> <div id="PrevSlideText"></div> </div> <div id="NextSlide"> <img id="NextSlideImage"/> <div id="NextSlideText"></div> </div>

These divs are simply there to hold the incoming data. Their display property of these divs is set to "none" in SlideShow.css, but if you were to comment this out, the page would show up as

follows:

The images in the upper corners are preloaded so that new slides load seamlessly. In the JavaScript code, we have to keep track of which slide we are on. If we're on the first slide, then only the following slide's data has been preloaded.
} if (CurSlide == 1) { PrevSlideNode = null; CurSlideNode = docElem.childNodes[0]; NextSlideNode = docElem.childNodes[1]; PrevSlideReady=false; NextSlideReady=true;

Notice that the global variable NextSlideReady is set to true indicating that the next slide should be loaded from the preloaded placeholder. This is checked in the NextSlide() function:
function NextSlide() { if (CurSlide < NumSlides) { CurSlide++; if (NextSlideReady) //Use data from NextSlide placeholder { document.getElementById("SlideText").innerHTML = document.getElementById("NextSlideText").innerHTML;

document.getElementById("SlideImage").src = document.getElementById("NextSlideImage").src; NextSlideReady=false; CurSlideLoaded=true; } GetSlide(); } else { document.getElementById("SlideMessage").innerHTML = "Already showing last slide."; setTimeout("document.getElementById('SlideMessage').innerHTML=' '", 2000); } } }

If we're on the last slide, then only the previous slide's data is preloaded.
else if (CurSlide == NumSlides) { PrevSlideNode = docElem.childNodes[0]; CurSlideNode = docElem.childNodes[1]; NextSlideNode = null; PrevSlideReady=true; NextSlideReady=false;

The global variable PrevSlideReady is set to true indicating that the previous slide should be loaded from the preloaded placeholder. This is checked in the PrevSlide() function:
function PrevSlide() { if (CurSlide > 1) { CurSlide--; if (PrevSlideReady) //Use data from PrevSlide placeholder { document.getElementById("SlideText").innerHTML = document.getElementById("PrevSlideText").innerHTML; document.getElementById("SlideImage").src = document.getElementById("PrevSlideImage").src; PrevSlideReady=false; CurSlideLoaded=true; } GetSlide(); } else { document.getElementById("SlideMessage").innerHTML = "Already showing first slide."; setTimeout("document.getElementById('SlideMessage').innerHTML=' '",2000); } }

For all other slides, both the previous and following slides' data is preloaded.
} else { PrevSlideNode = docElem.childNodes[0]; CurSlideNode = docElem.childNodes[1]; NextSlideNode = docElem.childNodes[2]; PrevSlideReady=true; NextSlideReady=true;

Both NextSlideReady and PrevSlideReady are set to true. Note that in the NextSlide() and PrevSlide() functions, CurSlideLoaded is set to true after a slide is loaded from preloaded data. This variable is checked in the ChangeSlide() function to decide whether or not to load the current slide from the newly downloaded data:
if (!CurSlideLoaded) //Use the data returned from the server { document.getElementById("SlideText").innerHTML = CurSlideNode.childNodes[0].firstChild.nodeValue + "<br/>"; document.getElementById("SlideText").innerHTML += CurSlideNode.childNodes[1].firstChild.nodeValue; document.getElementById("SlideImage").src = "Slides/" + CurSlideNode.childNodes[2].firstChild.nodeValue; }

Navigable Tables

The same techniques can be used to create navigable tables like the one shown below:

This screenshot shows the preloaded rows with a gray background. In practice, these rows would be hidden. Open AjaxApplications/Solutions/TableRows.html in your browser to try it out. To hide the preloaded rows, change the following lines in TablesRows.html:
<tbody id="PrevRows" style="background-color:gray;"></tbody> <tbody id="CurRows"></tbody> <tbody id="NextRows" style="background-color:gray"></tbody>

...to...
<tbody id="PrevRows" style="display:none;"></tbody> <tbody id="CurRows"></tbody> <tbody id="NextRows" style="display:none"></tbody>

Exercise: Create Navigable Table Rows (optional exercise)


Duration: 60 to 90 minutes. The purpose of this exercise is to try your hand at creating a small Ajax application almost from scratch. Actually, the server-side piece and the HTML are written for you. Your job is to write the JavaScript. You can use AjaxApplications/Demos/SlideShow-preloaded.jsp as a guide for the flow of the application. The exercise code is shown below.

Code Sample: AjaxApplications/Exercises/TableRows.html


<html> <head> <title>Table Rows</title> <link href="TableRows.css" type="text/css" rel="stylesheet"/> <script type="text/javascript" src="../../prototype.js"></script> <script type="text/javascript"> //WRITE YOUR CODE HERE. window.onload = init; </script> </head> <body> <h1>First 10 Presidents</h1> <table id="Table"> <thead> <tr> <th>President</th> <th>Years</th> <th>Image</th> </tr> </thead> <tbody id="PrevRows" style="color:red;"></tbody> <tbody id="CurRows"></tbody> <tbody id="NextRows" style="color:red"></tbody> <tfoot> <tr> <td colspan="3"> <form action="TableRows.html" onsubmit="return false" id="TableForm"> <input type="button" value="Previous" id="PrevButton" disabled="true"/> Rows <span id="CurRowStart">1</span> - <span id="CurRowEnd">2</span> of <span id="TotalRowsNum"></span> <input type="button" value="Next" id="NextButton"/> </form> </td> </tr> </tfoot> </table> </body> </html>

The server-side script (AjaxApplications/Exercises/TableRows.jsp) expects Row (the current row number) and RowsToShow (the number of rows to show) to be passed in. It will return

XML that looks like this: will depend on the value of RowsToShow (try 2).

The number of nodes

Note that tbody nodes have an insertRow() method, which returns the newly inserted row. Similarly, tr nodes have an insertCell() method, which returns the newly inserted cell. Both insertRow() and insertCell() take one argument: the position at which to insert the new element. Existing elements will get pushed ahead. Where is the solution?

Ajax Applications Conclusion


In this lesson of the Ajax tutorial, you have learned to apply some of the Ajax techniques you have learned. To continue to learn Ajax go to the top of this page and click on the next lesson in this Ajax Tutorial's Table of Contents. Last updated on 2009-03-22 All material in this Ajax Applications is copyright 2010 Webucator. The purpose of this website is to help you learn Ajax on your own and use of the website

You might also like