jQuery AJAX complete tutorial

jQuery is an amazing Javascript library that does all the heavy lifting for you so you can write less and do more (literally). AJAX stands for Asynchronous Javascript And XML. Truth be told these days the AJAX calls are Asynchronous Javascript And JSON(JavaScript Object Notation). Guess we still use the name AJAX probably because AJAJ sounds terrible 😀 . In this tutorial to understand how jQuery AJAX works we will build a small coffeeshop ordering application that does the following :

  1. Shows a list of orders pending
  2. Gives the user ability to add new orders
  3. Once an order has been processed user can remove the order

Well the result looks like this:
Overall look

Let’s build this project in a hands on manner. I instruct you step by step and you build the same on your system. I assume you know to download and install XAMPP (windows/Linux/Mac) and configure a database let’s call it ‘coffeeshop’ and inside that create a table ‘orders’. The structure of the table [id {int, auto-increment – true, primary key – true,}, customer_name {varchar, length-32}, drink_name {varchar, length -32}]. Once this is done go into the xampp folder and create a folder called webapi and create an empty file index.php . Then open netbeans (or anyother preferred ide) and create a PHP project with existing sources and point to the webapi folder and index.php file. Now from within the IDE create the directory structure and the files as shown below.

Technology used in the project :

  • PHP 5.5
  • MySql
  • jQuery 1.11.1
  • css 3 and html5

Directory structure of the project : (|| = folders and | = files)
||webapi————————————-(root – the project folder)

    ||includes—————————(to keep the php include files)
       |footer.html.php———–(the footer template)
       |header.html.php———–(the header template)

    ||js———————————-(javascripts folder)
      |jquery.js———————-(the jquery file)
      |custom.js———————-(the custom scripts we write)

    ||styles—————————–(to keep the css files)
      |styles.css———————-(the main css file)

    ||webservice—————————(to keep back-end database files)
        |dbconf.php————–(database configuration)
        |processdata.php————-(all back-end processing)

    |index.php———————————-(the main entry point of the application)

That’s it once we have created these files we can proceed with the next steps.
note : for jquery.js go to this link and copy and paste the entire content displayed on your browser to jquery.js file on your project. On a production environment we can point to a CDN network link for jquery but for development having a local copy is fine.

let’s look at the content of individual files and try and understand what each of them do.

1.header.html.php


<!doctype html>
<html lang="en">
    <head>
        <title>Welcome to web-service coffee store</title>
        <link rel="stylesheet" type="text/css" href="styles/style.css"/>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script type="text/javascript" src="js/custom.js"></script>
    </head>
    <body>
        <div class="wrapper">
        <div class="header">
            <h3>Welcome to the AJAX coffee shop. Below you see all the orders</h3>
        </div>


As you must have seen by now this file frankly has no php code just plain html that is why I name such template files as .html.php {and this must be looking partial html to you do not worry we will include the other structure by using the php include_once function.
2.footer.html.php

        <div class="footer">
            <h4>Copyright &COPY;<script>var dt = new Date(); document.write(dt.getFullYear())</script></h4>
        </div>
</div>

    </body>
</html>

As you can see this is again acting as a template and hence no php scripts inside. The advantage of creating header and footer separately as templates is that we can call them in any page via php and we need not have to copy and paste the same header and footer everywhere. In the bottom we have a nifty little javascript that prints the current year.As all the html files are complete let’s have a look at index.php and see how it puts everything together.

3.index.php

<?php
    include_once 'includes/header.html.php';
 ?>
 
<div class="orders">
    <ul>
        
    </ul>
</div>

<div class="addorders">
    <br>
    <h4>Add a new order</h4><hr>
    <label>Customer Name:</label><span><input type="text" name="customer_name" id="customer_name"/></span><span class="cname_error">Cannot be empty</span><br><br>
    <label>Drink Name:</label><span><input type="text" name="drink_name" id="drink_name"/></span><span class="dname_error">Cannot be empty</span><br><br>
    <button id="addorder">Add</button>
    <hr>
</div>  
<?php
    include_once 'includes/footer.html.php';
?>

As you might notice at the top and bottom we inlcude the header as well as the footer via php include_once function. Then we have a div class orders which has an ‘ul’ tag but is empty this is where we will do the jQuery AJAX magic to fill in out list of orders which are processing. Then you might as well notice in the add a new order section inside the input there are two span having classes “cname_error”and “dname_error” respectively and they have a text cannot be empty. But if you have noticed in the first image none of them are showing becuase we have set the css display property’s attribute to ‘none’. However when a user tries to submit with either or both the field’s empty we will do a bit of magic via jQuery and show the messages and highlight the input box. There are some more style elements attached to it to make them red. Anyway we will be looking at them in the next file. Before that see how the error is raised in the image below:

error when submit empty

4.style.css

/* 
    Created on : 4 Sep, 2014, 7:29:12 PM
    Author     : shakeel
*/

body{
    height:100%;
}
.wrapper{
    width:700px;
    height:100%;
    margin:0 auto;
}

div.header h3{
    margin-left: 3%;
}

.footer {
   clear: both;
    position: relative;
    z-index: 10;
    height: 3em;
    background:#ee5;
    text-align: center;
    width:100%;
}
 
div.footer h4{
    padding-top: 10px;
}

div.orders{
    width:80%;
    height:auto;
    margin: 0 auto;
}

div.orders li{
    background: #ee5;
    margin-bottom: 10px;
    padding: 5px;
    font-family: verdana;
    list-style: none;
    padding-left: 10px;
    padding-top: 25px;
}

span.removebtn{
    position: relative;
    left:95%;
    top:-70px;
    font-size:24px;
    cursor: pointer;
    color:red;
}

div.addorders{
    width:80%;
    height:auto;
    margin: 0 auto;
}

input#customer_name{
    position: relative;
    left:2%;
}

span.cname_error{
    color:red;
    position: relative;
    left:3%;
    display:none;
}

span.dname_error{
    color:red;
    position: relative;
    left:9%;
    display:none;
}

input#drink_name{
    position: relative;
    left:8%;
}

button#addorder{
  display : inline-block;
  cursor : pointer;
  border-style : solid;
  border-width : 1px;
  border-radius : 50px;
  padding : 10px 18px;
  box-shadow : 0 1px 4px rgba(0,0,0,.6);
  font-size : 9.5pt;
  font-weight : bold;
  color : green;
  text-shadow : 0 1px 3px rgba(0,0,0,.4);
  font-family : sans-serif;
  text-decoration : none;
  position: relative;
  left:28%;
}


Now that’s all with the styles needs of the site. It is not pretty but does the job 😛


*Most important section begins* This is where one by one we will see each part of code instead of looking at whole file at once and see how the javascript code written in the custom.js interacts with the processdata.php file and how the whole AJAX mechanism works. Let me tell you one point, when we use AJAX we do not have to refresh the page or reload the page yet we call backend server side files and get results and via jQuery manipulate the DOM [document object model] of the browser and inject new contents or remove contents there by providing a rich interaction experience to the end user.

As I mentioned earlier when the page loads first time if we have pending orders then they show up. That means in our orders table if some rows are availabale then we need to pull them and show them inside the empty ‘ul’ tags we had left in the index.php file. As you might know browsers work by sending HTTP request to server [called GET request] or by posting some data via HTTP request [called POST] to server. When we use the form element to do the posts then the browser gets refrshed and there is a postback which creates a perceivable delay to the end user and the interaction feels old times like. If you are using Firefox which I highly recommend then install an add-on called firebug this is required to easily debug javascript errors or just to see how the response request cycle works. Coming back to our example when the page loads we need to show only the data avialable on the server. For this we can do a GET request. Let’s see how this request is created and processed. First the creation of request. This exists in the custom.js file. The part of the file that handles the initial GET request is as follows :

$(document).ready(function(){
    
    //this one gets data from server
    
   $.ajax({
       url:'webservice/processdata.php',
       type:'GET',
       success: function(data)
       {
           data = $.parseJSON(data);
           var output = [];
           $.each(data, function(index,value){
            
            output.push("<li class="+value.id+"> Order id : "+value.id+" <br> Customer Name : "+value.customer_name+" <br> Drink : "+value.drink_name+" <br> <span id="+value.id+" class='removebtn'>X</span></li>");
               
           });
           $('div.orders ul').html(output.join(""));
       }
       
   });
});

By looking at the code we can easily see that we are calling a function wrapped inside $(document.ready) i.e when the dom is loaded the function gets excuted. Inside the anonymous function we use the $.ajax method of jQuery to make an AJAX call. The various parameters the call takes are :

  1. url : which points to our processdata.php file
  2. type : ‘GET’ this is important as the type will determine the request type
  3. success: on success we again write an anonymous function which build the DOM to be injected into the empty ‘ul’ tag lying on the index.php. if our call is successful we will have a JSON reply which will be in the ‘data’ variable which is in the parameter of the anonymous function. First we parse it using the $.parseJSON method, then since this can be an array we iterate over it using the $.each method of jQeury which takes data as parameter and we write again an anonymous function having an index and value parameter to iterrate over the array and we push the results of iteration in to the output variable using the ‘.push’ method. We build the ‘li’ tag and we add a span tag with a class remove button to decorate it and place it so as to it will work as the remove button. Finally we append all this inside the ‘ul’ tag via the jquery ‘.html’ method

Have a look on the console window of Firebug how this GET request is replied by server as 200 OK message and the response as a JSON on the image below:

GET request JSON response

Next we will have a look at the part of the processdata.php file which handles this ajax call and replies the result as JSON.

<?php
include_once 'dbconf.php';
if($_SERVER['REQUEST_METHOD'] == "GET")
{
    $data=array();
    $result = mysqli_query($con, "SELECT id,customer_name,drink_name FROM orders");
    while($row = mysqli_fetch_array($result,MYSQLI_ASSOC))
    {
        array_push($data, $row);
    }   
    
    echo json_encode($data);
  
}

The first line is a inlcude_once call to dbconf.php as this has the configuration required to make the database connections. As we know we have the AJAX request in the GET method to fulfil this request to make the call to the appropriate part of the code in the processdata.php we wrap the methods according to request types. Hence the first checking if($_SERVER[‘REQUEST_METHOD’] == “GET”). By this anything inside this condition only gets executed for the GET call. We create an array variable $data and then we retrieve the MySql query result as associative array so we can build a format suitable to JSON. We use the array_push method till we have as many rows in the database and finally we call the json_encode method to make the result as JSON ready to be read as the success parameter by the calling AJAX script in the custom.js. If you look at the whole process it is fairly easy right. If you are feeling a bit overwhelemed, take a break at this juncture and analyze what all you have done and how things have worked. 🙂 By the way I paste the dbconf.php below so you can use it now to check the above things worked for you or not.

<?php

$dbhost = "localhost";

$dbname = "coffeeshop";

$username = "root";

$password = "root";

// Create connection
$con=mysqli_connect($dbhost,$username,$password,$dbname);

// Check connection
if (mysqli_connect_errno()) {
  echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
?> 

Well so far we have managed to get the AJAX call going for the GET request and have built our DOM by using the result coming as JSON from server. Now the next part, which is adding data into server without postbacks and thus via ajax. This process is captured in our add order input boxes and the add button. Let’s have a look at the part of custom.js file that makes the POST call to add new orders.

$(document).ready(function(){
    
    //this one posts to server
    
    $('button#addorder').on("click",function(){
            var customer_name = $('input#customer_name').val();
            var drink_name = $('input#drink_name').val();
            if(customer_name === "")
            {
                $('span.cname_error').css({'display' : 'inline'});
                $('input#customer_name').css({'border' :'1px solid red'});
                
            }
            
            if(drink_name === "")
            {
                $('span.dname_error').css({'display' : 'inline'});
                $('input#drink_name').css({'border' :'1px solid red'});
                return false;
            }
            
            $.ajax({
                url:'webservice/processdata.php',
                type:'POST',
                data:{customer_name:customer_name,drink_name:drink_name},
                success:function(data){
                    data = $.parseJSON(data);
                    var output = [];
                    $.each(data, function(index,value){
            
                    output.push("<li class="+value.id+"> Order id : "+value.id+" <br> Customer Name : "+value.customer_name+" <br> Drink : "+value.drink_name+" <br> <span id="+value.id+" class='removebtn'>X</span></li>");
               
                    });
                    $('div.orders ul').html(output.join(""));
                    $('input#customer_name').val("");
                    $('input#drink_name').val("");
                }
            });
    });
    
});

Couple of differences here in this call are to be noticed and there are couple of other things going on here we should be paying attention to.

  1. We trigger this method once the DOM is built and the add order button is clicked as can be seen from the code we wrap the on click method on the click of the button and we have wrapped everything inside the $(document).ready method.
  2. Once the user clicks on the add order button we create two variables customer_name and drink_name and first thing we do is check if the customer_name is empty then we highlight by changing the css display property to inline from none thus ‘cannot be empty in red will pop up’ and also we make the input box highlighted by creating a border around it in red. It is important to note we do a return false if they are empty other wise the script will execute further and the AJAX call will happen and empty row will be inserted into database. We do the same thing to with the drink_name input box too.
  3. Two differences to notice in the AJAX call here is a. we set the type to POST and b. the motive of post is to send data to server we have another parameter called data in the call which we are sending as {Key,Value} pairs and we will be extracting them in the $_POST in processdata.php via the key.
  4. Finally when we get the success result we rebuild the DOM as there will be new row as done in case of the GET request and also we do one more thing we set the both input boxes value to empty so that user can type a new value and also it prevents accidental duplicate entries by multiple clicks on the add order button {smart hmm ! 😛 }

Now since we know how the request gets created for the ‘POST’ and how data is sent let’s see what we do in the ‘processdata.php’ to cater to this ‘POST’ request. The part of the processdata.php that handles this is as follows:

if($_SERVER['REQUEST_METHOD']== "POST")
{
    $customer_name = $_POST['customer_name'];
    $drink_name = $_POST['drink_name'];
    
    mysqli_query($con, "INSERT INTO orders (customer_name,drink_name) VALUES('$customer_name','$drink_name')");
 
    
    $data = array();
    $result = mysqli_query($con, "SELECT id,customer_name,drink_name FROM orders");
    while($row = mysqli_fetch_array($result,MYSQLI_ASSOC))
    {
        array_push($data, $row);
    }   
    
    echo json_encode($data);
    
}

As mentioned earlier we had two keys in the javascript ‘customer_name’ and ‘drink_name’ we get the values of it using $_POST[‘customer_name’] and $_POST[‘drink_name’] and store them in two variables $customer_name and $drink_name. Then we call an inser_into query to insert the records into the database. The thing to notice is we wrap the whole thing in $_SERVER[‘REQUEST_MENTHOD’] == “POST’. This is critical so that when the POST request comes from the jQuery only this part gets executed.

Now since we are done with the part where we are able to insert records into the database without doing any postback or page refresh, we can now proceed to the last bit which is deleteing the record to mimic the order completed scenario of our coffee shop. The part of the custom.js file that creates a request is as below:

$(document).ready(function(){
    // This one is to delete the completed order
    $(document).on("click",'span.removebtn',function()
    {
        var id = $(this).attr('id');
        
        $.ajax({
                url:'webservice/processdata.php?id='+id+'',
                type:'DELETE',
                success:function(id){
                  id = $.parseJSON(id);
                  $('li.'+id).fadeOut("slow",function()
                  {
                      $('li.'+id).remove();
                  });
                }
            });
        
    });
    
    
});

There are really some important things going on in this javascript which we should pay attention to understand.

  1. First thing is we are not capturing the click event directly of the span.removebtn if that was the case I could have written $(‘span.removebtn).on(click,function(){…}) but that is not possible. and it is one of the biggest newbie mistakes people learning jQuery do. The simple reason is this span is created dynamically so it is not available directly to the DOM thus we have to do something called ‘event delegation’. we capture the on the (document) and then use delegate to find the click event of span inside the document DOM. hence the code $(document).on(“click”,’span.removebtn’,function( { … })
  2. Then to find which order is being deleted we capture the id as you might remember when we were building the span we had given it the id property from the database so it exactly corresponds to the id in the table. In fact we had also given a class of id value to each ‘li’ the use of which will be knows below
  3. Once we have the id we send it as a query string to the server via this (url:’webservice/processdata.php?id=’+id+”,) and also we assign the type of call as ‘DELETE’
  4. Once we have a successful call we get the id of the deleted value from the server even though we have it with us to be doubly sure we use the one coming from server that way we know if there was an error we simply do not end up hiding the value in the DOM. To remove the list we use the .remove method on the li as we had appended the class of corresponding id to each ‘li’ and also we use the .fadeOut() method on the ‘li’ so that when we delete it fades out and then goes slowly making it look amazing 🙂

See below how that fade out works [well i have taken a screenshot] before it completely vanished 😀

fade effect on delete

That’s all in the Javascript part and let’s see the part of processdata.php file which handles this DELETE request.

if($_SERVER['REQUEST_METHOD']== "DELETE")
{
    $id = $_GET['id'];
    mysqli_query($con, "DELETE FROM orders where id='$id'");
    echo json_encode($id);
}

As always to fire the correct response we wrap this in the REQUEST_METHOD == “DELETE” so that when a delete request comes only this part gets executed. We extract the id to be deleted from the query string data we sent via $_GET[‘id’] and then we do a DELETE query to the database. Once that is done we wrap the $id as a JSON message and send it to the AJAX requests success message.

That’s it. I know this has been a pretty long tutorial. But since we covered the READ [“GET”], CREATE[“POST”] and DELETE requests and there were some nifty bits of javascript and also css to make them look good and give a good user experience this became long. I hope this tutorial will make approaching this subject easy for the reader. If any doubts you can post comment I will try to address them as soon as I can. For those who want to copy the entire files of custom.js and processdata.php I paste them below. But it would be better if you worked on it as explained instead of copying and pasting everything.

custom.js

$(document).ready(function(){
    
    //this one gets data from server
    
   $.ajax({
       url:'webservice/processdata.php',
       type:'GET',
       success: function(data)
       {
           data = $.parseJSON(data);
           var output = [];
           $.each(data, function(index,value){
            
            output.push("<li class="+value.id+"> Order id : "+value.id+" <br> Customer Name : "+value.customer_name+" <br> Drink : "+value.drink_name+" <br> <span id="+value.id+" class='removebtn'>X</span></li>");
               
           });
           $('div.orders ul').html(output.join(""));
       }
       
   });
});

$(document).ready(function(){
    
    //this one posts to server
    
    $('button#addorder').on("click",function(){
            var customer_name = $('input#customer_name').val();
            var drink_name = $('input#drink_name').val();
            if(customer_name === "")
            {
                $('span.cname_error').css({'display' : 'inline'});
                $('input#customer_name').css({'border' :'1px solid red'});
                return false;
                
            }
            
            if(drink_name === "")
            {
                $('span.dname_error').css({'display' : 'inline'});
                $('input#drink_name').css({'border' :'1px solid red'});
                return false;
            }
            
            $.ajax({
                url:'webservice/processdata.php',
                type:'POST',
                data:{customer_name:customer_name,drink_name:drink_name},
                success:function(data){
                    data = $.parseJSON(data);
                    var output = [];
                    $.each(data, function(index,value){
            
                    output.push("<li class="+value.id+"> Order id : "+value.id+" <br> Customer Name : "+value.customer_name+" <br> Drink : "+value.drink_name+" <br> <span id="+value.id+" class='removebtn'>X</span></li>");
               
                    });
                    $('div.orders ul').html(output.join(""));
                    $('input#customer_name').val("");
                    $('input#drink_name').val("");
                }
            });
    });
    
});

$(document).ready(function(){
    // This one is to delete the completed order
    $(document).on("click",'span.removebtn',function()
    {
        var id = $(this).attr('id');
        
        $.ajax({
                url:'webservice/processdata.php?id='+id+'',
                type:'DELETE',
                success:function(id){
                  id = $.parseJSON(id);
                  $('li.'+id).fadeOut("slow",function()
                  {
                      $('li.'+id).remove();
                  });
                }
            });
        
    });
    
    
});

processdata.php

<?php
include_once 'dbconf.php';
if($_SERVER['REQUEST_METHOD'] == "GET")
{
    $data=array();
    $result = mysqli_query($con, "SELECT id,customer_name,drink_name FROM orders");
    while($row = mysqli_fetch_array($result,MYSQLI_ASSOC))
    {
        array_push($data, $row);
    }   
    
    echo json_encode($data);
  
}

if($_SERVER['REQUEST_METHOD']== "POST")
{
    $customer_name = $_POST['customer_name'];
    $drink_name = $_POST['drink_name'];
    
    mysqli_query($con, "INSERT INTO orders (customer_name,drink_name) VALUES('$customer_name','$drink_name')");
 
    
    $data = array();
    $result = mysqli_query($con, "SELECT id,customer_name,drink_name FROM orders");
    while($row = mysqli_fetch_array($result,MYSQLI_ASSOC))
    {
        array_push($data, $row);
    }   
    
    echo json_encode($data);
    
}


if($_SERVER['REQUEST_METHOD']== "DELETE")
{
    $id = $_GET['id'];
    mysqli_query($con, "DELETE FROM orders where id='$id'");
    echo json_encode($id);
}

?>

Happy Coding 🙂

Thanks
Shakeel