Ajax Applications

Embed Size (px)

Citation preview

  • 8/6/2019 Ajax Applications

    1/24

    Login Form

    Have you ever forgotten your username or password for a website? Have you waited 10 secondsfor 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

    Login Form

    function Login(FORM)

    {

    var un = FORM.Username.value;

    var pw = FORM.Password.value;

    new Ajax.Request("Login.jsp",{method: "get",

  • 8/6/2019 Ajax Applications

    2/24

    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);}}

    Login Form

    Username:

    Password:

    The login information you entered does not match an account in our records.

    Please try again.

    Quick Lookup Form

  • 8/6/2019 Ajax Applications

    3/24

    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:

  • 8/6/2019 Ajax Applications

    4/24

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

    button becomes disabled:

  • 8/6/2019 Ajax Applications

    5/24

    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

    Order Lookup Form

    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;

  • 8/6/2019 Ajax Applications

    6/24

    }

    //Look up order number in databasenew 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="";document.getElementById("OrderNum").style.color="green";document.getElementById("SubmitButton").disabled=false;}}

    Lookup Form

    Enter an order number.

    Order Number:

    Comments:

    Code Sample: AjaxApplications/Demos/Lookup.jsp

  • 8/6/2019 Ajax Applications

    7/24

    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.

  • 8/6/2019 Ajax Applications

    8/24

    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 thepresidents 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

    Lookup Form

    function Lookup(FORM)

    {

    var year = FORM.Year.value;

    if (isNaN(year) || year.length != 4)

    {

  • 8/6/2019 Ajax Applications

    9/24

    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.*/

    Lookup Form

    Enter a year between 1789 and 1845 to find out who was president thatyear.

    Year:

    The server-side script is complete.

    Code Sample: AjaxApplications/Exercises/Lookup.jsp

  • 8/6/2019 Ajax Applications

    10/24

    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") + ")
    ");

    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 themap 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

    http://maps.google.com/http://maps.google.com/
  • 8/6/2019 Ajax Applications

    11/24

    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

    Slide Show

    var CurSlide=1; //Keeps track of current slidevar NumSlides = 10;

    function init()

    {

    document.getElementById("PrevButton").onclick=PrevSlide;

    document.getElementById("NextButton").onclick=NextSlide;

    document.getElementById("TotalSlideNum").innerHTML = NumSlides;

  • 8/6/2019 Ajax Applications

    12/24

    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 + "
    ";document.getElementById("SlideText").innerHTML +=docElem.childNodes[1].firstChild.nodeValue;

  • 8/6/2019 Ajax Applications

    13/24

    document.getElementById("SlideImage").src = "Slides/" +docElem.childNodes[2].firstChild.nodeValue;}

    window.onload = init;

    First 10 Presidents

    Slide 1 of

    Although this is pretty cool in and of itself, it can be made cooler by preloading the precedingand 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/SlideShow-

    preloaded.jsp

  • 8/6/2019 Ajax Applications

    14/24

    out.write("");out.write("" + rs.getString("FirstName") + " " +

    rs.getString("LastName") + "");out.write("" + rs.getString("StartYear") + "-" +

    rs.getString("EndYear") + "");out.write("" + rs.getString("ImagePath") + "");out.write("");}out.write("");}

    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.

  • 8/6/2019 Ajax Applications

    15/24

    Code Sample: AjaxApplications/Demos/SlideShow-

    preloaded.html

    Slide Show

    var CurSlide=1;

    var NumSlides = 10;

    var PrevSlideReady = false;var NextSlideReady = false;var 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)

  • 8/6/2019 Ajax Applications

    16/24

    {

    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 unnecessaryin IE

    Element.cleanWhitespace(NextSlideNode); //doesn't work and is unnecessary

    in IE

    } catch (e) {

    //alert(e.message);

    }

    PrevSlideReady=false;NextSlideReady=true;}

  • 8/6/2019 Ajax Applications

    17/24

    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 + "
    ";

    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 + "
    ";

    document.getElementById("PrevSlideText").innerHTML +=

    PrevSlideNode.childNodes[1].firstChild.nodeValue;

    document.getElementById("PrevSlideImage").src = "Slides/" +

    PrevSlideNode.childNodes[2].firstChild.nodeValue;

    }

    if (NextSlideNode)

    {

  • 8/6/2019 Ajax Applications

    18/24

    document.getElementById("NextSlideText").innerHTML =

    NextSlideNode.childNodes[0].firstChild.nodeValue + "
    ";

    document.getElementById("NextSlideText").innerHTML +=

    NextSlideNode.childNodes[1].firstChild.nodeValue;

    document.getElementById("NextSlideImage").src = "Slides/" +

    NextSlideNode.childNodes[2].firstChild.nodeValue;

    }

    CurSlideLoaded=false;

    }

    window.onload = init;

    First 10 Presidents

    Slide 1 of

    Code Explanation

    Notice these two divs in the HTML body:

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

  • 8/6/2019 Ajax Applications

    19/24

    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 thenext 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;

  • 8/6/2019 Ajax Applications

    20/24

    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 slideshould 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);

    }

    }

  • 8/6/2019 Ajax Applications

    21/24

    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 slideis 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 + "
    ";

    document.getElementById("SlideText").innerHTML +=

    CurSlideNode.childNodes[1].firstChild.nodeValue;

    document.getElementById("SlideImage").src = "Slides/" +

    CurSlideNode.childNodes[2].firstChild.nodeValue;

    }

    Navigable Tables

  • 8/6/2019 Ajax Applications

    22/24

    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:

    ...to...

  • 8/6/2019 Ajax Applications

    23/24

    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 writethe 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

    Table Rows

    //WRITE YOUR CODE HERE.

    window.onload = init;

    First 10 Presidents

    President

    Years

    Image

    Rows 1 - 2 of

  • 8/6/2019 Ajax Applications

    24/24

    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: The number of nodes

    will depend on the value of RowsToShow (try 2).

    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. BothinsertRow() 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

    http://www.learn-ajax-tutorial.com/AjaxApplications.cfm#menuHeadinghttp://www.learn-ajax-tutorial.com/AjaxApplications.cfm#menuHeading