Jump to content
Larry Ullman's Book Forums

Use Ajax With Pagination Script


Recommended Posts

Hello Larry and forum members,

 

I am trying to use Ajax with the pagination script (10.4) from chapter 10. Having read that the ajax .load() method is relatively easy to implement, I tried to see if it would work with the pagination script. Instead of the page reloading when a link is clicked, ajax should fetch the content from the URL and place it in the div with the "paginated content".

 

What I have tried does not work. Could someone PLEASE have a look at my script and tell me what I'm doing wrong?

 

Thank you for your assistance.

 

 

Herewith the faulty code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>test ajax</title>	
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>	
<script type="text/javascript">

$(function(){

    $('#pagination-links').on('click', 'a', function(e){

        e.preventDefault();
        var $this = $(this);
        var url = $this.attr('href');
	$('#container').load(url + '#paginated-content');
    

});
});	
 


</script>






</head>
<body>

<?php		
echo '<h1>Registered Users</h1>';

require ('mysqli_connect.php');


// Number of records to show per page:
$display = 8;

// Determine how many pages there are...
if (isset($_GET['p']) && is_numeric($_GET['p'])) { // Already been determined.
	$pages = $_GET['p'];
} else { // Need to determine.
 	// Count the number of records:
	$q = "SELECT COUNT(user_id) FROM users";
	$r = @mysqli_query ($dbc, $q);
	$row = @mysqli_fetch_array ($r, MYSQLI_NUM);
	$records = $row[0];
	// Calculate the number of pages...
	if ($records > $display) { // More than 1 page.
		$pages = ceil ($records/$display);
	} else {
		$pages = 1;
	}
} // End of p IF.

// Determine where in the database to start returning results...
if (isset($_GET['s']) && is_numeric($_GET['s'])) {
	$start = $_GET['s'];
} else {
	$start = 0;
}


	








// Table header:

echo
'<div id="container">
<div id="paginated-content">
';
// Define the query:
$q = "SELECT last_name, first_name, DATE_FORMAT(registration_date, '%M %d, %Y') AS dr, user_id FROM users LIMIT $start, $display";		
$r = @mysqli_query ($dbc, $q); // Run the query.
// Fetch and print all the records....
$bg = '#eeeeee'; 
while ($row = mysqli_fetch_array($r, MYSQLI_ASSOC)) {
	
	
		print'<a href="edit_user.php?id=' . $row['user_id'] . '">Edit</a>
		<a href="delete_user.php?id=' . $row['user_id'] . '">Delete</a>
		' . $row['last_name'] . '
		' . $row['first_name'] . '
		' . $row['dr'] . '
	
	';
} // End of WHILE loop.

echo'</div></div>';

mysqli_free_result ($r);
mysqli_close($dbc);

// Make the links to other pages, if necessary.
if ($pages > 1) {
	
	echo '<br /><p id="pagination-links">';
	$current_page = ($start/$display) + 1;
	
	// If it's not the first page, make a Previous button:
	if ($current_page != 1) {
		echo '<a href="view_users - try with ajax.php?s=' . ($start - $display) . '&p=' . $pages . '">Previous</a> ';
	}
	
	// Make all the numbered pages:
	for ($i = 1; $i <= $pages; $i++) {
		if ($i != $current_page) {
			echo '<a href="view_users - try with ajax.php?s=' . (($display * ($i - 1))) . '&p=' . $pages . '">' . $i . '</a> ';
		} else {
			echo $i . ' ';
		}
	} // End of FOR loop.
	
	// If it's not the last page, make a Next button:
	if ($current_page != $pages) {
		echo '<a href="view_users - try with ajax.php?s=' . ($start + $display) . '&p=' . $pages . '">Next</a>';
	}
	
	echo '</p>'; // Close the paragraph.
	
} // End of links section.
	

	
	
	
	
?>


	
</body>
</html>
Link to comment
Share on other sites

At first glance, the script above looks okay, but I don't know what the "view_users - try with ajax.php" script looks like.

Here're my recommendations to get started:

 

1) If you're not already using Chrome, please install it and load the above script into it.

2) Load Chrome DevTools and look at the Console tab for any JavaScript errors. Fix those if you can.

3) Next, look at the Network tab, and when you click on a pagination link, see what kind of HTTP request is made and also what kind of response is sent. If you find that your page is doing a hard reload, click the gray circle icon to record the network requests across page reloads so that you can catch it.

 

Between those two tabs, you should be able to determine the cause of any errors and resolve the issue(s).

If you're still not sure what to do, please let us know, and also post any information gleaned from the Chrome DevTools.

Lastly, please post the "view_users - try with ajax.php" script as well, if you feel it's relevant to the discussion.

 

Thank you.

Link to comment
Share on other sites

Hi HartleySan,

 

thanks for getting back to me on this, and for the recommendations.

 

You asked me about the "view_users - try with ajax.php" script. That is the script that I'm using - all of the code that I posted above is contained in that script. In the book it's called "view_users.php". The anchor/link goes back to the same "view_users - try with ajax.php" file.

 

I'll look for the Chrome browser. I'm already using Firebug and the Web Developer plugin. Do you know if I can use those as well, or must it be Chrome?

 

 

Thank you again for your help!

Link to comment
Share on other sites

You can use Firebug as well, but I prefer Chrome DevTools. I honestly don't know how to properly debug the issue in Firebug.

Whatever you're most comfortable with is fine. The main thing is that you need to check for JS errors as well as confirm the request and response that are being sent/received via Ajax.

 

Given that "view_users - try with ajax.php" is the script above, which is calling itself, I suspect that that is the problem. I would call a second PHP script, which simply takes the URL parameters, uses those to perform the DB query, and then echo back the DB response in JSON format.

 

If any of that doesn't make sense, please let me know.

Thanks.

Link to comment
Share on other sites

Hi HartleySan,

 

I'm not quite sure how to proceed with your suggestions.

 

What must the second script contain? Only the URL parameters? If so, how does this file receive the parameters from the “view users” PHP file? Would this script have to reproduce all of the PHP code up until the part where the query begins? That is, from the “number of records to show per page” up to and including “determine where in the database to start returning results”. If a link is clicked must the URL parameters first be sent to the second script, which performs the query, and then the .load() method retrieves the response in JSON format?

 

Please excuse all of these questions but I had to ask.

 

Ideally the pagination has to continue working as normal when JavaScript is disabled. I don't know if this is relevant to the issue at hand.

 

I'm sure you are busy, so I appreciate your help.

 

 

Thank you.

Link to comment
Share on other sites

Wagtail, the Ajax-requested script should basically receive the URL parameters, validate them if necessary, run the DB query based on the values of the URL parameters, and then echo back the results to the JS in your script in your original post.

 

As far as I know, the jQuery load method takes whatever you echo from your Ajax-requested script and just throws that directly into the element with the specified ID. As such, if you use the load method, you will likely have to form all the HTML markup you want to load into the page from the Ajax-requested PHP script.

 

Assuming that, if you were to do this, your flow might be something like the following:

 

view_users - try with ajax.php JavaScript



$(function () {
  $('#pagination-links').on('click', 'a', function (e) {
    $('#container').load(this.href.replace('view_users - try with ajax.php', 'ajax-requested-php-file'));
    e.preventDefault();
  }
}());


 

ajax-requested-php-file.php PHP



<?php
  // Include DB connection.
  
  $start = $_GET['s'];
  $pages = $_GET['p'];
  // Calculate $display variable here.
  
  $q = "SELECT last_name, first_name, DATE_FORMAT(registration_date, '%M %d, %Y') AS dr, user_id FROM users LIMIT $start, $display";
  
  // Perform query.
  
  $html = '';
  // Loop through results and form HTML markup string.
  
  echo $html;


 

And that's basically it. Here's a rundown of what the code does:

1) The jQuery on method attaches onclick event handlers to all the a elements on the page.

2) Whenever an a element is clicked, the jQuery load method is executed. The argument of the load method is formed by taking the value of the href attribute of the clicked on a element, and replacing the string 

"view_users - try with ajax.php" with "ajax-requested-php-file". This would, for example, change the URL used for the argument of the load method as follows:

 

view_users - try with ajax.php?s=0&p=5

ajax-requested-php-file.php?s=0&p=5

 

3) The ajax-requested-php-file.php file would be requested with the s and p URL parameters, which would be used as outlined in the code above.

4) After performing the query, you'd loop through the returned DB data and use that to build up all the HTML you need. That HTML would be stored in the $html variable.

5) The $html variable is echoed at the end of the script, which sends it back to the JS in the view_users - try with ajax.php file. As mentioned above, the load method automatically takes whatever is echoed back and just throws that directly into the element specified by ID.

 

Also, the nice thing about the above code is that in the event that JS is disabled, the regular links will be following, thus giving you that nice backward compatibility.

 

Beyond that, I'm not sure what else I can do to help. Please try out the above, and let us know whether it works or not.

Thanks.

  • Upvote 1
Link to comment
Share on other sites

Hi HartleySan,

 

thank you for posting and explaining the code. You have gone to some lengths to help me out!

 

What I can say is that the Ajax is working but there is some weird behaviour going on. When I first click a link, a second “registered users” heading appears, along with a second set of pagination links. The “view_users – try with ajax.php” file also continues to work even if I move the “ajax-requested-php-file.php” into another folder and clear the browser cache.

 

Perhaps I have left something out in the second script? I have renamed this file to "spot.php" to simplify things. I have modified the closing braces and parentheses in your function code, or are they correctly positioned?

 

 

 

Thanks again!

 

 

 

 

 

 

View_users - try with ajax.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>test ajax</title>	
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>	
<script type="text/javascript">

$(function () {
  $('#pagination-links').on('click', 'a', function (e) {
    $('#container').load(this.href.replace('view_users - try with ajax.php', 'spot.php'));
    e.preventDefault();
  });
});

</script>






</head>
<body>

<?php		
echo '<h1>Registered Users</h1>';

require ('mysqli_connect.php');


// Number of records to show per page:
$display = 8;

// Determine how many pages there are...
if (isset($_GET['p']) && is_numeric($_GET['p'])) { // Already been determined.
	$pages = $_GET['p'];
} else { // Need to determine.
 	// Count the number of records:
	$q = "SELECT COUNT(user_id) FROM users";
	$r = @mysqli_query ($dbc, $q);
	$row = @mysqli_fetch_array ($r, MYSQLI_NUM);
	$records = $row[0];
	// Calculate the number of pages...
	if ($records > $display) { // More than 1 page.
		$pages = ceil ($records/$display);
	} else {
		$pages = 1;
	}
} // End of p IF.

// Determine where in the database to start returning results...
if (isset($_GET['s']) && is_numeric($_GET['s'])) {
	$start = $_GET['s'];
} else {
	$start = 0;
}


	








// Table header:

echo
'<div id="container">
<div id="paginated-content">
';
// Define the query:
$q = "SELECT last_name, first_name, DATE_FORMAT(registration_date, '%M %d, %Y') AS dr, user_id FROM users LIMIT $start, $display";		
$r = @mysqli_query ($dbc, $q); // Run the query.
// Fetch and print all the records....

while ($row = mysqli_fetch_array($r, MYSQLI_ASSOC)) {
	
	
		print'<a href="edit_user.php?id=' . $row['user_id'] . '">Edit</a>
		<a href="delete_user.php?id=' . $row['user_id'] . '">Delete</a>
		' . $row['last_name'] . '
		' . $row['first_name'] . '
		' . $row['dr'] . '
	
	';
} // End of WHILE loop.

echo'</div></div>';

mysqli_free_result ($r);
mysqli_close($dbc);

// Make the links to other pages, if necessary.
if ($pages > 1) {
	
	echo '<br /><p id="pagination-links">';
	$current_page = ($start/$display) + 1;
	
	// If it's not the first page, make a Previous button:
	if ($current_page != 1) {
		echo '<a href="view_users - try with ajax.php?s=' . ($start - $display) . '&p=' . $pages . '">Previous</a> ';
	}
	
	// Make all the numbered pages:
	for ($i = 1; $i <= $pages; $i++) {
		if ($i != $current_page) {
			echo '<a href="view_users - try with ajax.php?s=' . (($display * ($i - 1))) . '&p=' . $pages . '">' . $i . '</a> ';
		} else {
			echo $i . ' ';
		}
	} // End of FOR loop.
	
	// If it's not the last page, make a Next button:
	if ($current_page != $pages) {
		echo '<a href="view_users - try with ajax.php?s=' . ($start + $display) . '&p=' . $pages . '">Next</a>';
	}
	
	echo '</p>'; // Close the paragraph.
	
} // End of links section.
	

	
	
	
	
?>


	
</body>
</html>

spot.php



<?php
  // Include DB connection.
require ('mysqli_connect.php');

  $start = $_GET['s'];
  $pages = $_GET['p'];
  
  // Calculate $display variable here.
$display = 8;

$q = "SELECT last_name, first_name, DATE_FORMAT(registration_date, '%M %d, %Y') AS dr, user_id FROM users LIMIT $start, $display";		
$r = @mysqli_query ($dbc, $q); // Run the query.
// Fetch and print all the records....

while ($row = mysqli_fetch_array($r, MYSQLI_ASSOC)) {
	
	
		print'<a href="edit_user.php?id=' . $row['user_id'] . '">Edit</a>
		<a href="delete_user.php?id=' . $row['user_id'] . '">Delete</a>
		' . $row['last_name'] . '
		' . $row['first_name'] . '
		' . $row['dr'] . '
	
	';
} // End of WHILE loop.


    

Link to comment
Share on other sites

Please keep in mind that according to the jQuery explanation page, the load method completely replaces the inner HTML of whatever element you load the Ajaxed content into.

To help you better debug the issues you are having, you may want to add the second and third optional arguments to the load method call, and use those to better debug your issue by using the Chrome DevTools console and the console.log method.

 

Also, instead of echoing (printing) out a little bit of markup each time through the while loop in spot.php, you may want to store all the markup into a variable in the while loop, and then after the while loop, echo out all the markup in the variable at once.

Link to comment
Share on other sites

Hello HartleySan,

 

I have discovered that my original script does work, but again with the heading and pagination links repeating themselves. I think it had something to do with the dash in the "view_users - test with ajax.php" file. I can't be sure.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>test ajax</title>	
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>	
<script type="text/javascript">

$(function(){

    $('#pagination-links').on('click', 'a', function(){

        
        var $this = $(this);
        var url = $this.attr('href');
	$('#container').load(url +'#paginated-content');
        return false;

});
});	
 


</script>






</head>
<body>

<?php		
echo '<h1>Registered Users</h1>';

require ('mysqli_connect.php');


// Number of records to show per page:
$display = 8;

// Determine how many pages there are...
if (isset($_GET['p']) && is_numeric($_GET['p'])) { // Already been determined.
	$pages = $_GET['p'];
} else { // Need to determine.
 	// Count the number of records:
	$q = "SELECT COUNT(user_id) FROM users";
	$r = @mysqli_query ($dbc, $q);
	$row = @mysqli_fetch_array ($r, MYSQLI_NUM);
	$records = $row[0];
	// Calculate the number of pages...
	if ($records > $display) { // More than 1 page.
		$pages = ceil ($records/$display);
	} else {
		$pages = 1;
	}
} // End of p IF.

// Determine where in the database to start returning results...
if (isset($_GET['s']) && is_numeric($_GET['s'])) {
	$start = $_GET['s'];
} else {
	$start = 0;
}


	








// Table header:

echo
'<div id="container">
<div id="paginated-content">
';
// Define the query:
$q = "SELECT last_name, first_name, DATE_FORMAT(registration_date, '%M %d, %Y') AS dr, user_id FROM users LIMIT $start, $display";		
$r = @mysqli_query ($dbc, $q); // Run the query.
// Fetch and print all the records....
$bg = '#eeeeee'; 
while ($row = mysqli_fetch_array($r, MYSQLI_ASSOC)) {
	
	
		print'<a href="edit_user.php?id=' . $row['user_id'] . '">Edit</a>
		<a href="delete_user.php?id=' . $row['user_id'] . '">Delete</a>
		' . $row['last_name'] . '
		' . $row['first_name'] . '
		' . $row['dr'] . '
	
	';
} // End of WHILE loop.

echo'</div></div>';

mysqli_free_result ($r);
mysqli_close($dbc);

// Make the links to other pages, if necessary.
if ($pages > 1) {
	
	echo '<br /><p id="pagination-links">';
	$current_page = ($start/$display) + 1;
	
	// If it's not the first page, make a Previous button:
	if ($current_page != 1) {
		echo '<a href="testajax.php?s=' . ($start - $display) . '&p=' . $pages . '">Previous</a> ';
	}
	
	// Make all the numbered pages:
	for ($i = 1; $i <= $pages; $i++) {
		if ($i != $current_page) {
			echo '<a href="testajax.php?s=' . (($display * ($i - 1))) . '&p=' . $pages . '">' . $i . '</a> ';
		} else {
			echo $i . ' ';
		}
	} // End of FOR loop.
	
	// If it's not the last page, make a Next button:
	if ($current_page != $pages) {
		echo '<a href="testajax.php?s=' . ($start + $display) . '&p=' . $pages . '">Next</a>';
	}
	
	echo '</p>'; // Close the paragraph.
	
} // End of links section.
	

	
	
	
	
?>


	
</body>
</html>

 

Also, instead of echoing (printing) out a little bit of markup each time through the while loop in spot.php, you may want to store all the markup into a variable in the while loop, and then after the while loop, echo out all the markup in the variable at once.

 

 

I have tried that but it would only return a single row. Do you mean like this?

while ($row = mysqli_fetch_array($r, MYSQLI_ASSOC)) {
	
	
	$hello = '<a href="edit_user.php?id=' . $row['user_id'] . '">Edit</a>
		<a href="delete_user.php?id=' . $row['user_id'] . '">Delete</a>
		' . $row['last_name'] . '
		' . $row['first_name'] . '
		' . $row['dr'] . '
	
	';
} // End of WHILE loop.

echo $hello;

Will keep on trying. Please let me know if there's anything else that might work.

 

 

Thank you for all of your help.

Link to comment
Share on other sites

Two things:

1) Try $hello .= instead of $hello =. Basically, you need to concatenate each of the strings together instead of reassigning a new string to the $hello variable (and overwriting the old string) each time through the loop.

 

2) Whenever I try to do something new (especially something big like learning how to use Ajax), I'd start out small and work my way up. I think that the complexities of your script aside from the Ajax may be complicating things, thus causing lots of confusion. Furthermore, while the jQuery load method is a simple shortcut, if you don't actually understand what's going on, it can be confusing. Lastly, short of you emailing me your scripts and DB file, since I can't test anything out myself, I'm limited in what I can do to help. I would, however, suggest setting up a simple script like the following, and then building it up little by little until you get what you want:

 

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Ajax test with jQuery load method</title>
  </head>
  <body>
    <a href="index.php?x=1">Click me to make an Ajax request with 1</a>
    <a href="index.php?x=2">Click me to make an Ajax request with 2</a>
    <a href="index.php?x=3">Click me to make an Ajax request with 3</a>
    <a href="index.php?x=4">Click me to make an Ajax request with 4</a>
    <a href="index.php?x=5">Click me to make an Ajax request with 5</a>
    <p>The result of the number in the link squared (as computed by Ajax) is:</p>
    <div id="result">
    </div>
    <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
    <script>
      $(document).on('click', 'a', function (evt) {
        console.log(this.href.replace('index.php', 'ajax_get.php'));
        
        $('#result').load(this.href.replace('index.php', 'ajax_get.php'));
        evt.preventDefault();
      });
    </script>
  </body>
</html>
 
ajax_get.php
<?php
  
  $x = (int) $_GET['x'];
  
  // Echo back $x squared.
  echo $x * $x;
 
Also, I recommend running index.html through your XAMPP localhost.

Please let me know if you have any further questions.

  • Upvote 1
Link to comment
Share on other sites

Hi HartleySan,

 

I must apologize profusely for not getting back to you sooner. You have made a lot of effort to help me, so I hope you don't find me too inconsiderate for not replying earlier to your previous post.

 

After playing around with the code I discovered that the Ajax pagination works if the 'paginated content' is loaded into the body of the webpage. The body tag needs to have an id: <body id="container">. This way there aren't any repeating headings or links. I hope someone can test this out for themselves and confirm that it all works fine.

$(function(){

    $('#pagination-links').on('click', 'a', function(){

        
        var $this = $(this);
        var url = $this.attr('href');
	$('#container').load(url +'#paginated-content');
        return false;

});
});	
 

Thanks again HartleySan.

Link to comment
Share on other sites

No, Wagtail, I did not think you were being inconsiderate.

Also, I doubt that anyone will be able to test out your script, as the real nuts and bolts of it are in the PHP script requested by Ajax that makes the DB request, which we can't do without your DB.

 

Anyway, you don't necessarily have to load the content into the body element (nor would you necessarily want to). Overwriting the inner-HTML of the body element will also overwrite any script elements within the body element, etc.; something you very likely don't want.

As you mentioned though, the key is to inject the Ajaxed HTML somewhere in the page so that it's overwriting the existing paginated content without overwriting anything more than that. A well placed ID on an element should easily handle that problem.

 

Also, I'm not 100% sure how the jQuery "on" method works, but I suspect that after you replace everything within the element with the ID "pagination-links" with new Ajaxed content, all your previous event handlers will be lost. What this essentially means is that unless you set up your event handlers again for the same set of links, when you try to click on a link after Ajaxing content once, you will no longer get Ajax links, but regular links. Put another way, the Ajax links will only work for you once, instead of continually, as many times as you want.

Please test out my theory though before you assume that that is indeed the case, but assuming it is, you'll have to account for that as well.

 

Good luck.

Link to comment
Share on other sites

 Share

×
×
  • Create New...