user10392798
user10392798

Reputation:

How to display the page with ajax?

I have a pagination that works correctly even I have added a filter to paginate more rows on the same page is to say that through the filter I can show 10 or 50 rows.

The small defect that I have in my code is that the page is reloaded, changing how many rows show and the same happens in the buttons of the pagination.

This is my code, everything is working on the same page index2.php.

<div id="wrapper">
    <div class="container">
        <div id="news-header" class="bootgrid-header container-fluid">
            <div class="row">
                <div class="col-sm-12 actionBar">
                    <div class="search-bar">
                        <input type="text" id="myInput" onkeyup="myFunction()" placeholder="What are you looking for?">
                    </div>
                    <div class="actions btn-group">
                        <?php
                            $select_quantity = '';
                            if (isset($_POST['amount_show'])) :
                                $select_quantity = $_POST['amount_show'];
                            endif;
                        ?>
                        <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
                            <select id="amount_show" name="amount_show" onchange="this.form.submit()">
                                <option value="10" <?php if ($select_quantity==10) echo "selected"; ?>>10</option>
                                <option value="25" <?php if ($select_quantity==25) echo "selected"; ?>>25</option>
                                <option value="50" <?php if ($select_quantity==50) echo "selected"; ?>>50</option>
                                <option value="100" <?php if ($select_quantity==100) echo "selected"; ?>>100</option>
                            </select>
                        </form>
                    </div>
                </div>
            </div>
        </div>
        <?php
            if (isset($_GET['page'])) :
                $page = $_GET['page'] ?: '';
            else :
                $page = 1;
            endif;

            if (isset($_POST['amount_show'])) :
                $records_by_page = $_POST['amount_show'];
            else :
                $records_by_page = 10;
            endif;

            $localization_sql = ($page-1) * $records_by_page;

            $sql = "SELECT id,title,description
                    FROM news
                    ORDER BY id DESC LIMIT $localization_sql, $records_by_page";
            $stmt = $con->prepare($sql);
            $stmt->execute();
            $stmt->store_result();
            if ($stmt->num_rows>0) :

            echo '<table id="myTable" class="table table-condensed table-hover table-striped bootgrid-table">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Title</th>
                    <th>Description</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>';

            $stmt->bind_result($id,$title,$description);
            while ($stmt->fetch()) :
                echo '<tr>
                    <td>'.$id.'</td>
                    <td>'.$title.'</td>
                    <td>'.$description.'</td>
                    <td>Edit</td>
                </tr>';
            endwhile;
            echo '</tbody>';
            echo '</table>';
            $stmt->close();


            $sql = "SELECT * FROM news";
            $stmt = $con->prepare($sql);
            $stmt->execute();
            $stmt->store_result();

            $BD_records = $stmt->num_rows;
            $stmt->close();
            $con->close();

            $total_page = ceil($BD_records / $records_by_page);
            $prev = $page - 1;
            $next = $page + 1;
            echo '<div class=pagination>
            <ul class="pagination">';
            if ($prev > 0) :
                echo "<li><a href='index2.php?page=1'><i class='icon-angle-double-arrow'></i></a></li>";
                echo "<li><a href='index2.php?page=$prev'><i class='icon-angle-left'></i></a></li>";
            endif;

            for ($i=1; $i<=$total_page; $i++) :
                if ($page==$i) :
                    echo "<li><a class=active>". $page . "</a></li>";
                else :
                    echo "<li><a href='index2.php?page=$i'>$i</a></li>";
                endif;
            endfor;


            if ($page < $total_page ) :
                echo "<li><a href='index2.php?page=$next'><i class='icon-angle-right'></i></a></li>";
                echo "<li><a href='index2.php?page=$total_page'><i class='icon-angle-double-right'></i></a></li>";
            endif;

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

            else :
                $stmt->close();
            endif;

        ?>
    </div>
</div>

While searching the web I found an ajax code, but sincerely, I did not manage the use ajax or javascript / jquery code.

You can explain how to implement this ajax code or how to avoid the small defect of reloading the page.

<script type="text/javascript">
$(document).ready(function() {  
    $('.pagination li a').on('click', function(){
        /*$('.items').html('<div class="loading"><img src="images/loading.gif" width="70px" height="70px"/><br/>Loading...</div>');*/
        $('.items').html('<div class="loading">Loading...</div>');

        var page = $(this).attr('data');        
        var dataString = 'page='+page;

        $.ajax({
            type: "GET",
            url: "ajax.php",
            data: dataString,
            success: function(data) {
                $('.items').fadeIn(2000).html(data);
                $('.pagination li').removeClass('active');
                $('.pagination li a[data="'+page+'"]').parent().addClass('active');

            }
        });
        return false;
    });              
});    
</script>

This is how my code works, as shown in the following image:

enter image description here

Upvotes: 6

Views: 6522

Answers (3)

msg
msg

Reputation: 8181

Let's start with the reason that causes your page to reload: The default browser actions. Several html elements cause the browser to navigate away from the current page. The ones we are concerned in this case are:

  • #amount_show form submission (the onchange function) that sends the new value via POST request.
  • The paginator itself (with a links) that tells the php script which records to retrieve via GET request.

Both values should be passed to the php script for it to be able to return the correct records, otherwise the amount parameter would be the default in the php script even if we have a different value selected. To be able to do that, we have to change the passing of the amount variable to a GET request.

Also, when changing the amount value we'll default to the first page to avoid recalculating the page number. Since the pagination links can therefore change dinamically, I'm not going to handle them in javascript but in php instead, since we already have a template and the calculations. This will make things easier to change down the line.

Let's tackle the javascript first:

$(document).ready(function() {
    // When we change the value of the select...
    //     evt contains the information about the event: 
    //         element receiving the action, the action itself, etc.

    $('#amount_show').change(function(evt) {
      // Cancel the default browser action
      evt.preventDefault()
      // Get the target url of the form (our php script)
      url = $(this).parent().attr('action')
      // Call the funtion that will be doing the request
      ajaxLoad(url)
    });

    // When we click a pagination link... (Explanation below)
    $('.items').on('click', '.pagination li a', function(evt) {
      evt.preventDefault()
      url = $(this).attr('href')
      ajaxLoad(url)
    });

    // Do the actual request
    function ajaxLoad(url) {
      // How many records do we want to show ?
      query_params = {
        amount_show: $('#amount_show').val()
      };
      // Show an indication that we are working
      $('.items').html('<div class="loading">Loading...</div>')
      $.ajax({
        type: "GET",
        url: url, // Call php, it will default to page 1 if there's no parameter set
        // When calling a link with a page parameter this will be smart
        // enough to append the variable to the query string correctly
        data: $.param(query_params),
        // Handle the data return. In a perfect world, this is always successful
        success: function(data) {
          // Insert the data in the document.
          $('.items').fadeOut('1000', function() { $(this).html(data) }).fadeIn('1000')
        }
      });
    }
  });

The line $('.items').on('click', '.pagination li a', function(evt) { attaches a delegate event listener to the .items element that will respond to the click events received by .pagination li a. The reason to do this instead of attaching directly to the element itself is two-fold:

  • Reduce the number of elements that we have to loop and attach a listener to.
  • Handle dynamic insertion of elements. When switching content, we are deleting the elements from the document, and their listeners with them. We would have to attach them again on every page load, otherwise with no listeners attached they would go back to the default action. But since this element doesn't change we won't have to do it.

Now for the php. Since you are interested in using a single file, I'm just going to move things around but it will (mostly) be what you have now.
Note: I may have misunderstood what you mean by having all in a single page. If this is a partial template that you are including from your main index, you'll have to change the link targets and action for the form to point to it, adjust some javascript selectors and you could skip the whole ajax request checking. Main changes:

  • Remove your onchange function call.
  • Change POST parameter to GET parameter.
  • Add a .items span to insert the elements in since it doesn't exist.
  • Determine if a page load is an ajax load or a regular one using X-Requested-With header. An alternative to this is returning a full response anyway and filtering it with jQuery.

    <?php
        if (isset($_GET['page'])) :
            $page = $_GET['page'] ?: '';
        else :
            $page = 1;
        endif;
    
        if (isset($_GET['amount_show'])) :
            $records_by_page = $_GET['amount_show'];
        else :
            $records_by_page = 10;
        endif;
    
        $localization_sql = ($page-1) * $records_by_page;
    
        $sql = "SELECT id,title,description
                FROM news
                ORDER BY id DESC LIMIT $localization_sql, $records_by_page";
        $stmt = $con->prepare($sql);
        $stmt->execute();
        $stmt->store_result();
    
        if ($stmt->num_rows>0) :
    
            // Start capturing the output
            ob_start();     
        ?>
        <table id="myTable" class="table table-condensed table-hover table-striped bootgrid-table">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Title</th>
                    <th>Description</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                <?php
                    $stmt->bind_result($id,$title,$description);
                    while ($stmt->fetch()) :
                        echo '<tr>
                            <td>'.$id.'</td>
                            <td>'.$title.'</td>
                            <td>'.$description.'</td>
                            <td>Edit</td>
                        </tr>';
                    endwhile;
                    $stmt->close();
                ?>
            </tbody>
        </table>
        <div class=pagination>
        <ul class="pagination">                
                <?php            
                  // When requesting an out-of-bounds page, this won't execute resulting in 
                  // a blank page with no paginator
                  $sql = "SELECT * FROM news";
                  $stmt = $con->prepare($sql);
                  $stmt->execute();
                  $stmt->store_result();
    
                  $BD_records = $stmt->num_rows;
                  $stmt->close();
                  $con->close();
    
                  $total_page = ceil($BD_records / $records_by_page);
                  $prev = $page - 1;
                  $next = $page + 1;
    
                  if ($prev > 0) :
                      echo "<li><a href='" . $_SERVER['PHP_SELF'] . "?page=1'><i class='icon-angle-double-arrow'></i></a></li>";
                      echo "<li><a href='" . $_SERVER['PHP_SELF'] . "?page=$prev'><i class='icon-angle-left'></i></a></li>";
                  endif;
    
                  for ($i=1; $i<=$total_page; $i++) :
                      if ($page==$i) :
                          echo "<li><a class='page-link active' >". $page . "</a></li>";
                      else :
                          echo "<li><a class='page-link' href='" . $_SERVER['PHP_SELF'] . "?page=$i'>$i</a></li>";
                      endif;
                  endfor;
    
                  if ($page < $total_page ) :
                      echo "<li><a class='page-link' href='index2.php?page=$next'><i class='icon-angle-right'></i></a></li>";
                      echo "<li><a class='page-link' href='index2.php?page=$total_page'><i class='icon-angle-double-right'></i></a></li>";
                  endif;
    
                  echo '</ul></div>';
    
                  // Get the output into a variable
                  $results_table = ob_get_clean();
    
              else :
                  $results_table = "<div>No results found</div>";
                  $stmt->close();
              endif;
    
              if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])) :
                  // If is an ajax request, output just the result table and exit
                  echo $results_table;
                  die;
              endif;
              // Print the whole page if its not an ajax request
          ?>
      <script type='text/javascript' src='//cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js'/>
      <script src='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.min.js' />
      <link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css' type='text/css' />
      <div id='wrapper'>
        <div class='container'>
          <div id='news-header' class='bootgrid-header container-fluid'>
            <div class='row'>
              <div class='col-sm-12 actionBar'>
                <div class='search-bar'>
                  <input type='text' id='myInput' placeholder='What are you looking for?'>
                </div>
                <div class='actions btn-group'>
                  <form action=<?php echo htmlspecialchars($_SERVER['PHP_SELF']);?>'>
                    <select id='amount_show' name='amount_show'>
                    </select>
                  </form>
                </div>
              </div>
            </div>
          </div>
    
          <span class='items'>
            <?php echo $results_table; ?>
          </span>
        </div>
      </div>
    

For completeness, the alternative method without separating the responses with php, is to filter the response with jQuery by doing the following in the ajax success callback (fades omitted):

results_table = $(data).find('.items').html()
$('.items').html(results_table)

This converts the response from the server into a jQuery object and allows to apply filtering functions as normal. We extract the content we are interested in (content of items: result table and pagination), then we just append it to the items container on our existing page.

UPDATE: I've posted a simplified example without database-related code here. I think there's something weird going on when copy&paste'ng code from/to the editor.

References

Upvotes: 2

bbenz
bbenz

Reputation: 139

Ajax is going to update information on your page without reloading your page. We want to separate the data from the HTML so we can change which data we're seeing. We can't do that if PHP is the tool writing the data into the HTML. So I recommend separating index2.php into several files. This example uses JSON.

Collect the data

ajax.php

<?php
$data_rows = array();

for ($i = 0; $i < 1000; $i++) {
    $data_rows[] = array(
        "id" => "id_$i",
        "title" => "title_$i",
        "description" => "description_$i",
    );
}

echo json_encode($data_rows, JSON_PRETTY_PRINT);

This is an example of some junk data, I don't know what data you need. The important thing here is to make an associative array of all the information you want, json_encode() the array, and then echo it. It's important that this is the only thing that gets echoed or printed! This won't work if you have anything else printing in this script.

Edit:

ajax.php

if (isset($_GET['page'])) :
                $page = $_GET['page'] ?: '';
            else :
                $page = 1;
            endif;

            if (isset($_POST['amount_show'])) :
                $records_by_page = $_POST['amount_show'];
            else :
                $records_by_page = 10;
            endif;

$sql = "SELECT id, title, description
FROM news
ORDER BY id DESC LIMIT $localization_sql, $records_by_page";
$result = $con->query($sql);
$data_rows = array();
while ($row = $result->fetch_assoc()) {
    $data_rows = $row;
}

echo json_encode($data_rows, JSON_PRETTY_PRINT);

Your original code includes this mysqli connection, this is data that I don't have access to so I can't test the efficacy of this script. However, this should present all of the data that you're asking about.

Ajax with jQuery

script.js

$(document).ready(function() {  
 $.ajax({
            type: "GET",
            url: "ajax.php",
            dataType: "json",
            success: function(data) {
                tableRows = '';
                for (let i = 0; i < data.length; i++) {
                    tableRows += `
                    <tr>
                        <td>${data[i].id}</td>
                        <td>${data[i].title}</td>
                        <td>${data[i].description}</td>
                        <td>Edit<td>
                    </tr>`;
                }
                $("#tbody-insert").html(tableRows);
            }
    });              
}); 

Set the url parameter of your ajax call to the name of the php file that's delivering the data. In the example I'm using JSON, it's important to set dataType: "json". jQuery will automatically parse this for you. You can see in the success parameter, data is the name of the php array we've created. I used a simple for loop to create a bunch of table rows, then inserted them into a table body that I've labeled with id="tbody-insert".

Present the data

index.html

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="script.js"></script>
<table id="myTable" class="table table-condensed table-hover table-striped bootgrid-table">
    <thead>
        <tr>
            <th>Id</th>
            <th>Title</th>
            <th>Description</th>
            <th>Action</th>
        </tr>
    </thead>
    <tbody id="tbody-insert">

    </tbody>
</table>

I've taken all the PHP out of your index page, it's not very flexible and it requires reloading the entire page before updating the information. The important points to note are the script tags, you need to include jQuery and you need to include the script.js. You also need to have an id for the table body that we're inserting information into. You can wrap your ajax in a function that gets called every time you want to paginate, and query ajax.php for different pages. I don't know the structure of your data so I can't help any further with that.

Upvotes: 5

Sven Liivak
Sven Liivak

Reputation: 1413

There's no point to start playing with jquery and async calls if even pure html is bit over the limit. In initial code you are mixing POST and GET, use just one.

<div id="wrapper">
    <div class="container">
        <div id="news-header" class="bootgrid-header container-fluid">
            <div class="row">
                <div class="col-sm-12 actionBar">
                    <div class="search-bar">
                        <input type="text" id="myInput" onkeyup="myFunction()" placeholder="What are you looking for?">
                    </div>
                    <div class="actions btn-group">
                        <?php
    //getting both - page and record_by_page from GET
                            $records_by_page = isset($_GET['amount_show'])?$_GET['amount_show']:10;
                            $page = isset($_GET['page'])?$_GET['page']:1;
    //put page value into form to send it together with amount_show
                        ?>
                        <form method="get" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
                            <select id="amount_show" name="amount_show" onchange="this.form.submit()">
                                <option value="10" <?php if ($records_by_page==10) echo "selected"; ?>>10</option>
                                <option value="25" <?php if ($records_by_page==25) echo "selected"; ?>>25</option>
                                <option value="50" <?php if ($records_by_page==50) echo "selected"; ?>>50</option>
                                <option value="100" <?php if ($records_by_page==100) echo "selected"; ?>>100</option>
                            </select>
                            <input type="hidden" id="page" name="page" value="<?php echo $page; ?>"></input>
                        </form>
                    </div>
                </div>
            </div>
        </div>
        <?php


            $localization_sql = ($page-1) * $records_by_page;

            $sql = "SELECT id,title,description
                    FROM news
                    ORDER BY id DESC LIMIT $localization_sql, $records_by_page";
            $stmt = $con->prepare($sql);
            $stmt->execute();
            $stmt->store_result();
            if ($stmt->num_rows>0) :

            echo '<table id="myTable" class="table table-condensed table-hover table-striped bootgrid-table">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Title</th>
                    <th>Description</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>';

            $stmt->bind_result($id,$title,$description);
            while ($stmt->fetch()) :
                echo '<tr>
                    <td>'.$id.'</td>
                    <td>'.$title.'</td>
                    <td>'.$description.'</td>
                    <td>Edit</td>
                </tr>';
            endwhile;
            echo '</tbody>';
            echo '</table>';
            $stmt->close();


            $sql = "SELECT * FROM news";
            $stmt = $con->prepare($sql);
            $stmt->execute();
            $stmt->store_result();

            $BD_records = $stmt->num_rows;
            $stmt->close();
            $con->close();

            $total_page = ceil($BD_records / $records_by_page);
            $prev = $page - 1;
            $next = $page + 1;
            echo '<div class=pagination>
            <ul class="pagination">';
//add amount_show to each request
            if ($prev > 0) :
                echo "<li><a href='pagination.php?page=1&amount_show=$records_by_page'><i class='icon-angle-double-arrow'></i></a></li>";
                echo "<li><a href='pagination.php?page=$prev&amount_show=$records_by_page'><i class='icon-angle-left'></i></a></li>";
            endif;

            for ($i=1; $i<=$total_page; $i++) :
                if ($page==$i) :
                    echo "<li><a class=active>". $page . "</a></li>";
                else :
                    echo "<li><a href='pagination.php?page=$i&amount_show=$records_by_page'>$i</a></li>";
                endif;
            endfor;


            if ($page < $total_page ) :
                echo "<li><a href='pagination.php?page=$next&amount_show=$records_by_page'><i class='icon-angle-right'></i></a></li>";
                echo "<li><a href='pagination.php?page=$total_page&amount_show=$records_by_page'><i class='icon-angle-double-right'></i></a></li>";
            endif;

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

            else :
                $stmt->close();
            endif;

        ?>
    </div>
</div>  

Upvotes: -1

Related Questions