Lab 11

Lab 11

JavaScript & AJAX


Goals

Learn about...

  1. How JavaScript is used in the browser
  2. How to call server-side script using JavaScript, i.e., asychronous HTTP requests
  3. How to receive data asychronously via JavaScript
  4. How to select, create and manipulate HTML elements in JavaScript

1. Getting data from server using JavaScript

  1. In your lab11 folder, create a new file called p1.html and copy the following code
    <!doctype html>
    <html lang="en">
    
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
    <title>Part 1</title>
    
    <body>
    
    <div class="container">
    </div>
    
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
    
    <script>
    
    </script>
    
    </body>
    
    </html>	
    
  2. Give the container div and id, i.e., <div class="container" id="ctnr">
  3. We will use this id to select the container div and add content from a server-side script called p1.php
  4. In your lab11 folder, create a new file called p1.php and copy the following code
    <?
    	
    require_once('site_db.php');
    
    $r = run_query("SELECT userid, type FROM users");
    
    echo '
      <table class="table">
        <tr>
          <th>Action</th>
          <th>User ID</th>
          <th>Type</th>
        </tr>';
    
    
    
    while($u = $r->fetch_assoc()) {
      echo '
        <tr>
          <td>
            <button class="btn btn-danger">Delete</button>
          </td>
          <td>'.$u['userid'].'</td>
          <td>'.$u['type'].'</td>
        </tr>';
    }
    
    echo '</table>';
    
    ?>
    
  5. Notice it uses the site_db.php file.
  6. Copy site_db.php from your project2 folder to your lab11 folder.
  7. Upload site_db.php and p1.php to the server and test the script. It should output an un-styled table of users with a delete button next to each userid.
  8. Add the following code the inside the script tag of p1.html:
    <script>
      function responseHandler() {
        alert(this.response);
      }
    
      var xhr = new XMLHttpRequest();
      xhr.addEventListener("load", responseHandler);
      xhr.open("GET", "p1.php");
      xhr.send();	
    </script>
    
  9. Upload p1.html to the server and test the script. When the page is loaded, JavaScript sends a request for p1.php and displays it using an alert.
  10. Instead of displaying it with an alert, we will select the container div (id="ctnr") and insert it as the innerHTML.
  11. Replace alert(this.response) with the following:
    var c = document.getElementById("ctnr");
    c.innerHTML = this.response;
    
  12. document is a pointer to the DOM of the current loaded webpage.
  13. We use getElementById to create a pointer c to the container div so that it is rendered with Bootstrap's CSS.
  14. c.innerHTML is the container div's content.
  15. Upload p1.html to the server again and test the script. When the page is loaded, the table should now appear inside the container div.
  16. If you view the document source code, you will not see the table because we modified the DOM, not the source file.
  17. If you inspect the document, you will see the table if you expand the container div's content.

2. Sending the data more efficiently

  1. First, save p1.html as p2.html
  2. The problem with sending the user data this way is that it includes all the table tags, which is almost as significant as the data itself.
  3. Instead, we can send the data using more compact JavaScript Object Notation (JSON).
  4. In your lab11 folder, create a new file called p2.php and copy the following code:
    <?
    	
    require_once('site_db.php');
    
    $r = run_query("SELECT userid, type FROM users");
    
    $list = array();
    while($u = $r->fetch_row()) {
    	array_push($list, $u);
    }
    
    echo json_encode($list);
    
    ?>
    
  5. Upload the p2.php and test it on the server.
  6. You will see that it echo's the user data as JavaScript encoded 2D array, which is much more compact that HTML. In the past, data was sent using XML, which is even more "wordy" than HTML. JSON is now the prefered way to send data to/from web browsers and web servers.
  7. Again, make sure you have saved p1.html as p2.html
  8. Change p2.html so that we make an HTTP request for p2.php instead of p1.php:
    var xhr = new XMLHttpRequest();
    xhr.addEventListener("load", responseHandler);
    xhr.open("GET", "p2.php");
    xhr.send();
    
  9. Change p2.html to put the table inside of the container as follows:
    <div class="container" id="ctnr">
      <table class="table">
        <thead>
          <tr>
            <th>Action</th>
            <th>User ID</th>
            <th>Type</th>
          </tr>	
        </thead>
        <tbody id="tbl">
        </tbody>
      </table>
    </div>
    
  10. Notice that we gave the tbody an id.
  11. Upload p2.html to the server and test it. You should see the JSON encode string loaded in the page, instead of the table.
  12. Next, we will change the responseHandler to generate the table from the JSON encoded string. Thus, we are using the user's web browser to do some work, instead of generating the table on our web server.
  13. Replace all the code in the current responseHandler function with the following code that loops over the 2D array to creat the table:
    function responseHandler() {
    	
      var table = document.getElementById("tbl");
      
      var tdata = this.response;
      var tarray = JSON.parse(tdata);
    	
    	
      for(var i = 0; i < tarray.length; i++) {
    
        var trow = document.createElement("tr");
    
        var td1 = document.createElement("td");
        var td2 = document.createElement("td");
        var td3 = document.createElement("td");
    
        td1.innerHTML = '<button class="btn btn-danger">delete</button>';
        td2.innerHTML = tarray[i][0];
        td3.innerHTML = tarray[i][1];
    
        trow.appendChild(td1);
        trow.appendChild(td2);
        trow.appendChild(td3);
    
        table.appendChild(trow);		
      }
    }	
    
  14. Please read the following:
    • this.response is literally whatever p2.php will echo. In this case, p2.php echos a JSON encoded string that represents a 2D array.
    • JSON.parse converts a JSON encoded string into an actual JavaScript data type, i.e., 2D array. Thus, tarray is a 2D array.
    • createElement creates new HTML objects.
    • innerHTML is used to set the contents of the new HTML objects.
    • We append the three td elements into a row.
    • Finally, we append the row into the table body.

3. Dynamcally inserting users

  1. First, save p2.html as p3.html
  2. Create a new file called p3.php in your lab11 and add the following code:
    <?
    require_once('site_db.php');
    
    $userid = $_GET['userid'];
    $passwd = $_GET['passwd'];
    $type = $_GET['type'];
    
    run_query("INSERT INTO users VALUE ('$userid','$passwd','$type')");
    ?>
    
  3. Notice that the code above only does the minimal amount of work on the server to do the actual insertion. It does not output any web page or HTML.
  4. Change p3.html and add the following form elements inside the container and above the table:
    <div class="container">
    
      <div class="form-group">
        <label for="userid">UserID</label>
        <input type="text" class="form-control" id="userid">
      </div>
      <div class="form-group">
        <label for="passwd">Password</label>
        <input type="password" class="form-control" id="passwd">
      </div>
      <div class="form-group">
        <label for="type">Type</label>
        <input type="text" class="form-control" id="type">
      </div>
      <button class="btn btn-primary" id="sbtn">Submit</button>
    
      <hr>
    
      <table class="table">
        <thead>
          <tr>
            <th>Action</th>
            <th>User ID</th>
            <th>Type</th>
          </tr>	
        </thead>
        <tbody id="tbl">
        </tbody>
      </table>
    </div>
    	
    </div>
    
  5. Notice that there is no form action. And, notice that the submit button has an id. Remember the submit button's id.
  6. Next, we will use Asychronous JavaScript (AJAX) to send the form data to the server when the submit button is clicked.
  7. Inside the script tag of p3.html add the following event listener. You can add it anywhere inside the script tag:
    	
    var submitBtn = document.getElementById("sbtn");
    submitBtn.addEventListener("click", insertUser);
    
  8. Notice that we are creating a submitBtn object and assigning it to the actual submit button that we identified using its id, i.e., sbtn. Notice that we are adding an event listener so that the function insertUser is called when the submitBtn object is clicked.
  9. Finally, we will define the insertUser function
  10. Inside the script tag of p.html, add the following function. You can add it anywhere inside the script tag:
    function insertUser() {
    
    	// Get the submitted form values	
    	var usr = document.getElementById("userid").value;
    	var psw = document.getElementById("passwd").value;
    	var typ = document.getElementById("type").value;
    	
    	// Get the table body
    	var table = document.getElementById("tbl");
    
    	// Create a new table row
    	var trow = document.createElement("tr");
    
    
    	// Create three new table data cells
    	var td1 = document.createElement("td");
    	var td2 = document.createElement("td");
    	var td3 = document.createElement("td");
    
    	// Put content and value into the table data cells
    	td1.innerHTML = '<button class="btn btn-danger">delete</button>';
    	td2.innerHTML = usr;
    	td3.innerHTML = typ;
    	
    	// Append the cells to the row
    	trow.appendChild(td1);
    	trow.appendChild(td2);
    	trow.appendChild(td3);
    	
    	// Insert the row as the first child of the table body
    	table.insertBefore(trow, table.firstChild);	
    	
    	// Request p3.php and pass usr, psw and typ in the URL using the GET method
    	var xhr = new XMLHttpRequest();
    	xhr.open("GET", "p3.php?userid="+usr+"&passwd="+psw+"&type="+typ);
    	xhr.send();	
    }	
    
  11. Read the comments above and then consider the following:
  12. Instead of requesting/generating a new web page to give the user feedback, we dynamically insert the new user into the table at the very top indicating that the operation was successful. However, we do not know this for certain as the user is actually inserted by the last three lines, i.e., the AJAX request.
  13. Consider the AJAX request below:
     var xhr = new XMLHttpRequest();
     xhr.open("GET", "p3.php?userid="+usr+"&passwd="+psw+"&type="+typ);
     xhr.send();	
    
  14. If the user typed "eric", "poop" and "1" into the form and clicked submit, this is similar to typing "p3.php?userid=eric&passwd=poop&type=1" into a browser's address bar. However, JavaScript handles the response and the page is never reloaded.
  15. To be sure the insertion was successful, we could have p3.php return the three values and then we could create an event listener to dynamically add the values to the displayed table only if p3.php responds without error. If p3.php returns an error (null or 0), we could then display the error using an alert or by dynamically inserting a text message into the form.
  16. You do not have to change this script, but in class on Friday, we will put this all together and it is important to understand that there are two operations:
    • Client-side insert into displayed table
    • Server-side insert into actual table

Note that there is no part 4. It was combined with part 3.


5. Actually deleting from the database

  1. Download p5s.html and save it to your lab11 folder
  2. Copy the code from p5.txt and save it as p5.php in your lab11 folder
  3. The instructor will explain this code above in class

DELIVERABLE

Nothing. You get full credit for using the 2-hour lab time productively.