AJAX & JSON

 

AJAX

AJAX (Asynchronous JavaScript + XML) allow webpages to send data to and retrieve from a database server asynchronously (in the background) without interfering with the display and behavior of the existing page. Using AJAX, a webpage can change its content in real-time. By using AJAX, we do not have to load a new webpage. Instead, we update the current webpage.

AJAX webpages provide a smoother visual appearance to users, as the webpage does not need to reload. Instead, only those parts of the webpage that need to be updated are changed. The rest of the webpage remains unchanged.

First File (send an AJAX request to read data from a database)

ajax_search.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AJAX Example</title>
<script>
async function ajaxListModel(model) 
{
    let url = "ajax_get_one_model.php";   /* name of file to send request to */
    let urlParameters = "model=" + model; /* Construct a url parameter string to POST to fileName */
    
    try
    {
        const response = await fetch(url,
        {
             method: "POST",
             headers: {'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
             body: urlParameters
        });

        updateWebpage(await response.text());
    }
    catch (error)
    {
        console.log("Fetch failed: ", error);
    }


    /* use the fetched data to change the content of the webpage */
    function updateWebpage(responseText)
    {
        document.getElementById('model').innerHTML = responseText;
    }
}
</script>
</head>
<body>

<form>
<select name = 'users' onchange = 'ajaxListModel(this.value)'>
  <option value = "">Select a model</option>
  <option value = "corolla">Corolla</option>
  <option value = "yaris">Yaris</option>
  </select>
</form>
<br>
<div id = 'model'>Model details will be listed here.</div>

</body>
</html>
 

Second File (access the database in response to an AJAX request. Every "echo" in this file will be sent as data to the file that issued the AJAX request.)

ajax_get_one_model.php

WARNING: If a php file is being used to fulfill an AJAX request, then it must not have any sourrounding html tags (such as DOCTYPE, HTHM, HEAD, TITLE or BODY). This can be seen in the example below:

<?php
/* Validate and assign input data */
$model = ltrim(rtrim(filter_input(INPUT_POST, "model", FILTER_SANITIZE_STRING)));
if (empty($model))
{
    echo "Invalid input parameter.";
    exit();
}


/* Include "configuration.php" file */
require_once "configuration.php";


/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


/* Perform query */
$query = "SELECT id, model, colour, year, price FROM toyota WHERE model = :model";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":model", $model, PDO::PARAM_STR);         
$statement->execute();



/* Manipulate the query result */
if ($statement->rowCount() > 0)
{
    echo "<table>";
    $result = $statement->fetchAll(PDO::FETCH_OBJ);
    foreach ($result as $row)
    {
        echo "<tr>";
        echo "<td>" . $row->model . "</td><td>" . $row->colour . "</td><td>" . $row->year . "</td><td>" . $row->price . "</td><td>" . $row->id . "</td>";
        echo "</tr>";
    }
    echo "</table>";
}
echo "<p>" . $statement->rowCount() . " records found.</p>";



/* Provide a link for the user to proceed to a new webpage or automatically redirect to a new webpage */
/* This webpage never actually displays. Instead, it runs in the background on the server. */
/* The "echo" data is automatically sent back inside the "http_request.responseText" of the calling function. */
/* Therefore, no feedback or way to proceed is necessary. */
?>

AJAX allows us to update a webpage without leaving the webpage. This feature is used a lot in modern websites. List various examples of where AJAX is used.

In the example above, the models listed in the drop-down list are hard coded as 'corolla' and 'yaris'. Write php code to create the drop-down list of available models from the database.

Solution php file for the above question:

model_list.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHP drop-down list example</title>
<script>
    async function ajaxListModel(model)
    {
        let url = "ajax_get_one_model.php";    /* use POST method to send data to ajaxSearch.php */
        let urlParameters = "model=" + model;  /* Construct a url parameter string to POST to fileName */

        try
        {
            const response = await fetch(url,
            {
                method: "POST",
                headers: {'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                body: urlParameters
            });

            updateWebpage(await response.text());
        }
        catch (error)
        {
            console.log("Fetch failed: ", error);
        }


        /* use the fetched data to change the content of the webpage */
        function updateWebpage(responseText)
        {
            document.getElementById('model').innerHTML = responseText;
        }
    }
</script>
</head>
<body>

<form>
<select name = "users" onchange = "ajaxListModel(this.value)">

<?php
/* Include "configuration.php" file */
require_once "configuration.php";


/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


/* Perform query */
/* SELECT DISTINCT ensures that no duplicate model names are selected */
$query = "SELECT DISTINCT model FROM toyota";
$statement = $dbConnection->prepare($query);
$statement->execute();



/* Manipulate the query result */
if ($statement->rowCount() > 0)
{
    $result = $statement->fetchAll(PDO::FETCH_OBJ);
    echo "<option value=''>Select a model</option>";
    foreach ($result as $row)
    {
        echo "<option value='" . $row->model . "'>" . $row->model . "</option>";
    }
}
?>

</select>
</form>
<br>
<div id = "model">Model details will be listed here.</div>
</body>
</html>

JSON

JSON (JavaScript Object Notation) files allow data to be stored as a string. We can use JSON to pass data back from an AJAX request.

In our examples, returning the data as a JSON string means that we can generate the html table to hold the car details after we get the data from the database code. This removes the need to output any html code in the database server code. This is cleaner, as it separates the page creation code from the database query code.

First File (send an AJAX request to read data from a database and process the returned JSON string)

ajax_json_search.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AJAX JSON search Example</title>
<script>
async function ajaxListModel(model) 
{
    let url = "ajax_get_one_model.php";    /* use POST method to send data to ajax_json_search.php */
    let urlParameters = "model=" + model;  /* Construct a url parameter string to POST to fileName */
    
    try
    {
        const response = await fetch(url,
        {
            method: "POST",
            headers: {'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
            body: urlParameters
        });

        updateWebpage(await response.json());
    }
    catch (error)
    {
        console.log("Fetch failed: ", error);
    }


    /* use the fetched data to change the content of the webpage */
    function updateWebpage(jsonData)           
    {
        let htmlString = "<table>";
        
        for(let i = 0; i < jsonData.length; i++)
        {
            htmlString += "<tr><td>" + jsonData[i].model + "</td><td>" + jsonData[i].colour + "</td><td>" + jsonData[i].year + "</td><td>" + jsonData[i].price + "</td></tr>";
        }
        htmlString += "</table><br>" + jsonData.length + " records found.";
        document.getElementById('model').innerHTML = htmlString;  
    }
}
</script>
</head>
<body>

<form>
<select name = "users" onchange = "ajaxListModel(this.value)">

<?php
/* Include "configuration.php" file */
require_once "configuration.php";


/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


/* Validate and assign input data */
/* As we are selecting all records from the table, we do not need any input value */



/* Perform query */
/* SELECT DISTINCT ensures that no duplicate model names are selected */
$query = "SELECT DISTINCT model FROM toyota";
$statement = $dbConnection->prepare($query);
$statement->execute();



/* Manipulate the query result */
if ($statement->rowCount() > 0)
{
    $result = $statement->fetchAll(PDO::FETCH_OBJ);
    echo "<option value=''>Select a model</option>";
    foreach ($result as $row)
    {
        echo "<option value='" . $row->model . "'>" . $row->model . "</option>";
    }
}
?>

</select>
</form>
<br>
<div id = "model">Model details will be listed here.</div>
</body>
</html>

 

Second File (access the database in response to an AJAX request and return a JSON string containing the database's record details)

ajax_get_one_model.php

WARNING: If a php file is being used to fulfill an AJAX request, then it must not have any sourrounding html tags (such as DOCTYPE, HTHM, HEAD, TITLE or BODY). This can be seen in the example below:

<?php
/* Validate and assign input data */
$model = ltrim(rtrim(filter_input(INPUT_POST, "model", FILTER_SANITIZE_STRING)));
if (empty($model))
{
    echo "[]"; // send back an empty JSON string
    exit();
}


/* Include "configuration.php" file */
require_once "configuration.php";


/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


/* Perform query */
$query = "SELECT id, model, colour, year, price FROM toyota WHERE model = :model";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":model", $model, PDO::PARAM_STR);        
$statement->execute();


/* Manipulate the query result */
$json = "[";
if ($statement->rowCount() > 0)
{
    /* Get field information for all fields */
    $isFirstRecord = true;
    $result = $statement->fetchAll(PDO::FETCH_OBJ);
    foreach ($result as $row)
    {
        if(!$isFirstRecord)
        {
            $json .= ",";
        }
        
        /* NOTE: json strings MUST have double quotes around the attribute names, as shown below */
        $json .= '{"model":"' . $row->model . '","colour":"' . $row->colour  . '","year":' . strval($row->year)  . ',"price":' . strval($row->price)  . '}';
        
        $isFirstRecord = false;
    }  
}     
$json .= "]";

/* Send the $json string back to the webpage that sent the AJAX request */
echo $json;


/* Provide a link for the user to proceed to a new webpage or automatically redirect to a new webpage */
/* This webpage never actually displays. Instead, it runs in the background on the server. */
/* The data contained in the line of code "echo $json;" is automatically sent back inside the "http_request.responseText" of the calling function. */
/* Therefore, no feedback or way to proceed is necessary. */
?>

Removing all PHP from a HTML file

AJAX can be used to remove all php code from a html file. This makes our code much cleaner, as we totally separate the data from the view.

In the previous example, embedded php code was used to display the list of available models. The code below uses AJAX to remove this php code.

First File (sends two different AJAX requests to read data from a database and process the returned JSON strings)

ajax_json_search.html (note that this can now be a HTML file rather than a PHP file)
<!DOCTYPE html>
<html>
<head>
<title>AJAX JSON search Example</title>
<script>
    async function ajaxListAllModels()
    {
        let url = "ajax_get_all_models.php";   /* use POST method to send data to ajax_json_search.php */
        let urlParameters = "";   /* Construct a url parameter string to POST to fileName */

        try
        {
            const response = await fetch(url,
            {
                method: "POST",
                headers: {'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                body: urlParameters
            });

            updateWebpage(await response.json());
        }
        catch (error)
        {
            console.log("Fetch failed: ", error);
        }


        /* use the fetched data to change the content of the webpage */
        function updateWebpage(jsonData)
        {
            let htmlString = "<select name = 'users' onchange = 'ajaxListModel(this.value)'>";

            for (let i = 0; i < jsonData.length; i++)
            {
                htmlString += "<option value='" + jsonData[i].model + "'>" + jsonData[i].model + "</option>";
            }
            htmlString += "</select>";
            
            document.getElementById('listOfModels').innerHTML = htmlString;
        }
    }


    async function ajaxListModel(model)
    {
        let url = "ajax_get_one_model.php";    /* use POST method to send data to ajax_json_search.php */
        let urlParameters = "model=" + model;  /* Construct a url parameter string to POST to fileName */

        try
        {
            const response = await fetch(url,
            {
                method: "POST",
                headers: {'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                body: urlParameters
            });

            updateWebpage(await response.json());
        }
        catch (error)
        {
            console.log("Fetch failed: ", error);
        }


        /* use the fetched data to change the content of the webpage */
        function updateWebpage(jsonData)
        {
            let htmlString = "<table>";

            for (let i = 0; i < jsonData.length; i++)
            {
                htmlString += "<tr><td>" + jsonData[i].model + "</td><td>" + jsonData[i].colour + "</td><td>" + jsonData[i].year + "</td><td>" + jsonData[i].price + "</td></tr>";
            }
            
            htmlString += "</table><br>" + jsonData.length + " records found.";
            document.getElementById('model').innerHTML = htmlString;
        }
    }
</script>
</head>
<body onload="ajaxListAllModels()">

<div id="listOfModels"></div><br>
<div id = "model">Model details will be listed here.</div>

</body>
</html>

Second File (get the list of models from the database)

ajax_get_all_models.php

WARNING: If a php file is being used to fulfill an AJAX request, then it must not have any sourrounding html tags (such as DOCTYPE, HTHM, HEAD, TITLE or BODY). This can be seen in the example below:

<?php
/* Include "configuration.php" file */
require_once "configuration.php";


/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


/* Perform query */
$query = "SELECT DISTINCT model FROM toyota";
$statement = $dbConnection->prepare($query);       
$statement->execute();


/* Manipulate the query result */
$json = "[";
if ($statement->rowCount() > 0)
{
    /* Get field information for all fields */
    $isFirstRecord = true;
    $result = $statement->fetchAll(PDO::FETCH_OBJ);
    foreach ($result as $row)
    {
        if(!$isFirstRecord)
        {
            $json .= ",";
        }
        
        /* NOTE: json strings MUST have double quotes around the attribute names, as shown below */
        $json .= '{"model":"' . $row->model . '"}';
        
        $isFirstRecord = false;
    }  
}     
$json .= "]";

/* Send the $json string back to the webpage that sent the AJAX request */
echo $json;




/* Provide a link for the user to proceed to a new webpage or automatically redirect to a new webpage */
/* This webpage never actually displays. Instead, it runs in the background on the server. */
/* The data contained in the line of code "echo $json;" is automatically sent back inside the "http_request.responseText" of the calling function. */
/* Therefore, no feedback or way to proceed is necessary. */
?>

Third File (get the list of all cars of a particular model from the database)

ajax_get_one_model.php

WARNING: If a php file is being used to fulfill an AJAX request, then it must not have any sourrounding html tags (such as DOCTYPE, HTHM, HEAD, TITLE or BODY). This can be seen in the example below:

<?php
/* Validate and assign input data */
$model = ltrim(rtrim(filter_input(INPUT_POST, "model", FILTER_SANITIZE_STRING)));
if (empty($model))
{
    echo "[]"; // send back an empty JSON string
    exit();
}


/* Include "configuration.php" file */
require_once "configuration.php";


/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


/* Perform query */
$query = "SELECT id, model, colour, year, price FROM toyota WHERE model = :model";
$statement = $dbConnection->prepare($query);
 $statement->bindParam(":model", $model, PDO::PARAM_STR);        
$statement->execute();



/* Manipulate the query result */
$json = "[";
if ($statement->rowCount() > 0)
{
    /* Get field information for all fields */
    $isFirstRecord = true;
    $result = $statement->fetchAll(PDO::FETCH_OBJ);
    foreach ($result as $row)
    {
        if(!$isFirstRecord)
        {
            $json .= ",";
        }
        
        /* NOTE: json strings MUST have double quotes around the attribute names, as shown below */
        $json .= '{"model":"' . $row->model . '","colour":"' . $row->colour  . '","year":' . strval($row->year)  . ',"price":' . strval($row->price)  . '}';
        
        $isFirstRecord = false;
    }  
}     
$json .= "]";

/* Send the $json string back to the webpage that sent the AJAX request */
echo $json;




/* Provide a link for the user to proceed to a new webpage or automatically redirect to a new webpage */
/* This webpage never actually displays. Instead, it runs in the background on the server. */
/* The data contained in the line of code "echo $json;" is automatically sent back inside the "http_request.responseText" of the calling function. */
/* Therefore, no feedback or way to proceed is necessary. */
?>

Using JSON allows programmers to format the returned data at the client side. This makes the code more maintainable. Place the output from the above example into a "ul" list instead of a "table".

Using JSON means that the view of the data is seperated from the actual data. This means that different files can use the data in different ways. Write code in a new file that only displays the model, year and price of a car.

JSON Text Files

JSON data does not have to be taken from a database. Instead, it can be stored in a text file. The text file must be of file-type ".json" and it must contain a valid JSON structure, as shown below.

car_details.json
[
    {
        "model": "avensis",
        "colour": "red",
        "year": "2017",
        "price": "35000"
    },
    {
        "model": "yaris",
        "colour": "white",
        "year": "2015",
        "price": "1000"
    },
    {
        "model": "corolla",
        "colour": "white",
        "year": "2017",
        "price": "20000"
    },
    {
        "model": "avensis",
        "colour": "red",
        "year": "2015",
        "price": "15000"
    },
    {
        "model": "corolla",
        "colour": "black",
        "year": "2010",
        "price": "4000"
    }
]

The JSON data shown above is stored in a file called "car_details.json" and is read in the example below.

Example of reading from a JSON file (Run Example)

read_from_json.php
<!DOCTYPE html>
<html>
<head>
<title>AJAX read JSON file example</title>
<script>
async function ajaxListAllCars()
{
    let url = "car_details.json";      /* JSON file */
    let urlParameters = "";      /* Leave empty, as no parameter is passed to the JSON file */

    try
    {
        const response = await fetch(url,
        {
            method: "POST",
            headers: {'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
            body: urlParameters
        });

        updateWebpage(await response.json());
    }
    catch (error)
    {
        console.log("Fetch failed: ", error);
    }


    /* use the fetched data to change the content of the webpage */
    function updateWebpage(jsonData)
    {
        let htmlString = "<table>";

        for (let i = 0; i < jsonData.length; i++)
        {
            htmlString += "<tr><td>" + jsonData[i].model + "</td><td>" + jsonData[i].colour + "</td><td>" + jsonData[i].year + "</td><td>" + jsonData[i].price + "</td></tr>";
        }

        htmlString += "</table><br>" + jsonData.length + " records found.";
        document.getElementById('model').innerHTML = htmlString;
    }
}
</script>
</head>
<body onload="ajaxListAllCars()">

<div id="listOfModels"></div><br>
<div id = "model">Model details will be listed here.</div>

</body>
</html>

Post JSON Data to PHP File

We can use the AJAX fetch() method to POST url parameters as a json string to a php or other file.

post_json.php
<!DOCTYPE html>
<html>
    <head>
        <title>AJAX JSON search Example</title>
        <script>
            async function ajaxListAllModels()
            {
                let url = "ajax_get_all_models.php";   /* use POST method to send data to ajax_json_search.php */
                let urlParameters = "";   /* Construct a url parameter string to POST to fileName */

                try
                {
                    const response = await fetch(url,
                            {
                                method: "POST",
                                headers: {'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                                body: urlParameters
                            });

                    updateWebpage(await response.json());
                }
                catch (error)
                {
                    console.log("Fetch failed: ", error);
                }


                /* use the fetched data to change the content of the webpage */
                function updateWebpage(jsonData)
                {
                    let htmlString = "<select name = 'users' onchange = 'ajaxListModel(this.value)'>";
                    for (let i = 0; i < jsonData.length; i++)
                    {
                        htmlString += "<option value='" + jsonData[i].model + "'>" + jsonData[i].model + "</option>";
                    }
                    htmlString += "</select>";

                    document.getElementById('listOfModels').innerHTML = htmlString;
                    ajaxListModel(jsonData[0].model);
                }
            }


            async function ajaxListModel(model)
            {
                let url = "post_json_transaction.php";    /* use POST method to send data to ajax_json_search.php */
                let jsonParameters = {model: model};

                try
                {
                    const response = await fetch(url,
                            {
                                method: "POST",
                                headers: {'Accept': 'application/json', 'Content-Type': 'application/json'},
                                body: JSON.stringify(jsonParameters)
                            });

                    updateWebpage(await response.json());
                }
                catch (error)
                {
                    console.log("Fetch failed: ", error);
                }


                /* use the fetched data to change the content of the webpage */
                function updateWebpage(jsonData)
                {
                    let htmlString = "<table>";

                    for (let i = 0; i < jsonData.length; i++)
                    {
                        htmlString += "<tr><td>" + jsonData[i].model + "</td><td>" + jsonData[i].colour + "</td><td>" + jsonData[i].year + "</td><td>" + jsonData[i].price + "</td></tr>";
                    }

                    htmlString += "</table><br>" + jsonData.length + " records found.";
                    document.getElementById('model').innerHTML = htmlString;
                }
            }
        </script>
    </head>
    <body onload="ajaxListAllModels()">

        <div id="listOfModels"></div><br>
        <div id = "model">Model details will be listed here.</div>

    </body>
</html>
post_json_transaction.php
<?php
header("Content-Type: application/json; charset=UTF-8");

/* read the json data that was sent to this file */
$jsonData = json_decode(file_get_contents('php://input'), true);

/* Validate and assign input data */
$model = $jsonData['model'];  // read the model data from jsonData
if (empty($model)) 
{
    echo "[]"; // send back an empty JSON string
    exit();
}


/* Include "configuration.php" file */
require_once "configuration.php";


/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


/* Perform query */
$query = "SELECT id, model, colour, year, price FROM toyota WHERE model = :model";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":model", $model, PDO::PARAM_STR);
$statement->execute();



/* Manipulate the query result */
$json = "[";
if ($statement->rowCount() > 0) {
    /* Get field information for all fields */
    $isFirstRecord = true;
    $result = $statement->fetchAll(PDO::FETCH_OBJ);
    foreach ($result as $row) {
        if (!$isFirstRecord) {
            $json .= ",";
        }

        /* NOTE: json strings MUST have double quotes around the attribute names, as shown below */
        $json .= '{"model":"' . $row->model . '","colour":"' . $row->colour . '","year":' . strval($row->year) . ',"price":' . strval($row->price) . '}';

        $isFirstRecord = false;
    }
}
$json .= "]";

/* Send the $json string back to the webpage that sent the AJAX request */
echo $json;




/* Provide a link for the user to proceed to a new webpage or automatically redirect to a new webpage */
/* This webpage never actually displays. Instead, it runs in the background on the server. */
/* The data contained in the line of code "echo $json;" is automatically sent back inside the "http_request.responseText" of the calling function. */
/* Therefore, no feedback or way to proceed is necessary. */
?>
 
<div align="center"><a href="../../versionC/index.html" title="DKIT Lecture notes homepage for Derek O&#39; Reilly, Dundalk Institute of Technology (DKIT), Dundalk, County Louth, Ireland. Copyright Derek O&#39; Reilly, DKIT." target="_parent" style='font-size:0;color:white;background-color:white'>&nbsp;</a></div>