Difference between revisions of "6CS028 Workshop - Ajax"

From mi-linux
Jump to navigationJump to search
 
(78 intermediate revisions by 2 users not shown)
Line 1: Line 1:
[[Main Page]] >> [[CP3207|Advanced Web Technologies]] >> [[Web Application Developpment - Workbook|Workbook]] >> Week 05
+
[[Main Page]] >> [[6CS028|Advanced Web Development]] >> [[6CS028 - Workbook|Workbook]] >> Week 04 - Ajax
  
Today we are going to use Ajax to create a simple Live Search. There are 3 simple steps:
+
'''Important''': this is a CodeIgniter example, but it is easily adaptable to Laravel.
  
# Step 1 – Create the web page
+
== The JSON data ==
# Step 2 – Create the client-side script (JavaScript)
 
# Step 3 – Create the server-side script (PHP)
 
  
Let’s get started!
+
First, let's create a page that will output JSON data from our existing "news" database table, like this:
 
+
* https://mi-linux.wlv.ac.uk/~in9352/ci4/public/index.php/ajax/get/hello
== Step 1 – Create the web page ==
 
 
 
First we obviously need to create our web page. Let’s keep it nice and simple:
 
  
 +
Create a '''new''' controller called '''Ajax.php''', with the following code:
 
<pre>
 
<pre>
<HTML>
+
<?php
  <HEAD>
 
    <TITLE>Test Ajax</TITLE>
 
    <SCRIPT type="text/javascript" src="ajax.js"></SCRIPT>
 
  </HEAD>
 
  <BODY>
 
    Check name: <INPUT type="text" id="a_name" onblur="send_request(this);">
 
    <DIV id="div_result"></DIV>
 
  </BODY>
 
</HTML>
 
</pre>
 
 
 
There are 2 important elements in our body:
 
* The text box that is going to trigger the JavaScript event. As you can see the onBlur event (which is triggered when you tab out of the text box) calls a send_request function, which is located in a separate file (see next step!)
 
* The div element, in which the response will be displayed
 
  
== Step 2 – Create the client-side script (JavaScript) ==
+
namespace App\Controllers;
  
This file implements the client-side part of our Ajax transaction. It looks a bit complicated at first, but let’s break it down into its 3 main parts:
+
use App\Models\NewsModel;
  
* The initliveSearchReq() function creates the XMLHttpRequest object, which is the object we need to send the HTTP request to the server. As you can see this function is a bit messy, as this object is created differently depending on the browser. It seems to work on all browsers this way, but you might know simpler, tidier way?
+
class Ajax extends BaseController
* The send_request() function is the one called by the JavaScrtipt event (see step 1). It creates the XMLHttpRequest object (by calling the function above), specifies which function should be run when the response comes back (DisplayResult in our case), and finally sends the request to the server. Note how it passes the text typed by the user as a parameter in the URL.
 
* The DisplayResult() function is called when the response comes back from the server. As you can see it simply inserts the response text in our div_result element.
 
 
 
<pre>
 
// ajax.js
 
 
 
var liveSearchReq = false;
 
var name = "";
 
 
var isIE = false;
 
// on !IE we only have to initialize it once
 
if (window.XMLHttpRequest)
 
 
{
 
{
liveSearchReq = new XMLHttpRequest();
+
public function get($slug = null)
}
+
{
 +
$model = model(NewsModel::class);
 +
$data = $model->getNews($slug);
  
// +----------------------------------------------------------------------+
+
print(json_encode($data));
// | Init HTTP object
 
// +----------------------------------------------------------------------+
 
function initliveSearchReq()
 
{
 
  if(window.XMLHttpRequest)
 
  {
 
    // Firefox et autres
 
  liveSearchReq = new XMLHttpRequest();
 
  }
 
  else if(window.ActiveXObject)
 
  {
 
    // Internet Explorer
 
  try
 
    {
 
  liveSearchReq = new ActiveXObject("Msxml2.XMLHTTP");
 
  }
 
    catch (e)
 
    {
 
      liveSearchReq = new ActiveXObject("Microsoft.XMLHTTP");
 
  }
 
  }
 
}
 
// +----------------------------------------------------------------------+
 
// | Send request
 
// +----------------------------------------------------------------------+
 
function send_request(t)
 
{
 
  // Get user input
 
  name = t.value;
 
  if(name!="")
 
  {
 
    // Create HTTP object
 
    initliveSearchReq();
 
 
 
  // Set function to handle response
 
  liveSearchReq.onreadystatechange= DisplayResult;
 
 
 
  // Send request
 
  liveSearchReq.open("GET", "ajax.php?name=" + name);
 
 
 
    // Finish transaction
 
  liveSearchReq.send(null);
 
  }
 
  else
 
  {
 
  var  sh = document.getElementById("div_result");
 
  sh.innerHTML = "Please enter value";   
 
  }
 
}
 
// +----------------------------------------------------------------------+
 
// | Handle response
 
// +----------------------------------------------------------------------+
 
function DisplayResult()
 
{
 
if (liveSearchReq.readyState == 4)
 
  {
 
var  sh = document.getElementById("div_result");
 
sh.innerHTML = liveSearchReq.responseText;
 
 
}
 
}
 +
 
}
 
}
 
</pre>
 
</pre>
 +
Note: it is very similar to our previous news controller. The function above selects a given news items from our model (as per before), but converts the data to JSON and simply prints it to the browser.
  
== Step 3 – Create the server-side script (PHP) ==
+
== The Ajax call ==
 +
Next, we need to write some JavaScript that will "fetch" data from the URL above.
  
Now all we need is the server-side part of our Ajax transaction. It’s a simple PHP file that reads the parameters passed in the URL, and then queries the database. I will let you implement the database access… this example features a “fake” database check (a simple if statement).
+
In your '''existing overview.php''' view, make the following changes:
  
 +
Add a container paragraph (maybe right at the top for now), that will be used to display the data coming back from the request:
 
<pre>
 
<pre>
<?
+
<p id="ajaxArticle"></p>
  // ajax.php
+
</pre>
  
  // Get value coming from request
+
Next, add a button for each article, that calls the JavaScript code, passing the current article's slug:
  $name = $_GET['name'];
+
<pre>
 +
<p><button onclick="getData('<?= esc($news_item['slug'], 'url') ?>')">View article via Ajax</button></p>
 +
</pre>
 +
Note: the above should be inside the foreach loop, right after the existing "view article" link.
  
  // Connect to DB
+
Finally, add the JavaScript block at the bottom of the file:
 
+
<pre>
  // Check if name exists in table
+
<script>
 
+
function getData(slug) {
  if($name=="Alix")
+
    echo("This name is in the database");
+
// Fetch data
  else
+
fetch('https://mi-linux.wlv.ac.uk/~in9352/ci4/public/ajax/get/' + slug)
    echo("This name is NOT in the database :(");
+
 
+
  // Convert response string to json object
  //Close connection
+
  .then(response => response.json())
 +
  .then(response => {
  
?>
+
// Copy one element of response to our HTML paragraph
 +
document.getElementById("ajaxArticle").innerHTML = response.title + ": " + response.text;
 +
  })
 +
  .catch(err => {
 +
 +
// Display errors in console
 +
console.log(err);
 +
});
 +
}
 +
</script>
 
</pre>
 
</pre>
 +
Notes:
 +
* you will have to change the URL in the fetch statement, to match yours.
 +
* the document.getElementById("ajaxArticle").innerHTML allows you to write to the HTML element specified earlier. You could have more than one!
 +
* you might eventually wish to move this to an external JS file, as it's more efficient and tidy.
  
== All done ==
+
Here is mine:
 
+
* [https://mi-linux.wlv.ac.uk/~in9352/ci4/public/index.php/newsajax https://mi-linux.wlv.ac.uk/~in9352/ci4/public/index.php/newsajax]
Your live search should now work…
+
* Try pressing the various "View article via Ajax" buttons, and see how the article is displayed at the top.
 +
* Look in the developer tools / network tab, and note how each button triggers an HTTP request behind the scenes! Look at their preview.

Latest revision as of 16:12, 9 March 2023

Main Page >> Advanced Web Development >> Workbook >> Week 04 - Ajax

Important: this is a CodeIgniter example, but it is easily adaptable to Laravel.

The JSON data

First, let's create a page that will output JSON data from our existing "news" database table, like this:

Create a new controller called Ajax.php, with the following code:

<?php

namespace App\Controllers;

use App\Models\NewsModel;

class Ajax extends BaseController
{
	public function get($slug = null)
	{
		$model = model(NewsModel::class);
		$data = $model->getNews($slug);

		print(json_encode($data));
	}
	
}

Note: it is very similar to our previous news controller. The function above selects a given news items from our model (as per before), but converts the data to JSON and simply prints it to the browser.

The Ajax call

Next, we need to write some JavaScript that will "fetch" data from the URL above.

In your existing overview.php view, make the following changes:

Add a container paragraph (maybe right at the top for now), that will be used to display the data coming back from the request:

<p id="ajaxArticle"></p>

Next, add a button for each article, that calls the JavaScript code, passing the current article's slug:

<p><button onclick="getData('<?= esc($news_item['slug'], 'url') ?>')">View article via Ajax</button></p>

Note: the above should be inside the foreach loop, right after the existing "view article" link.

Finally, add the JavaScript block at the bottom of the file:

<script>
	function getData(slug) {
		
		// Fetch data
		fetch('https://mi-linux.wlv.ac.uk/~in9352/ci4/public/ajax/get/' + slug)
			
		  // Convert response string to json object
		  .then(response => response.json())
		  .then(response => {

			// Copy one element of response to our HTML paragraph
			document.getElementById("ajaxArticle").innerHTML = response.title + ": " + response.text;
		  })
		  .catch(err => {
			
			// Display errors in console
			console.log(err);
		});
	}
</script>

Notes:

  • you will have to change the URL in the fetch statement, to match yours.
  • the document.getElementById("ajaxArticle").innerHTML allows you to write to the HTML element specified earlier. You could have more than one!
  • you might eventually wish to move this to an external JS file, as it's more efficient and tidy.

Here is mine: