6

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

  • 1
    So have you actually tried the ajax? If so, what was the result? How did you try to resolve any issues that you had? If you did _not_ try yet, then please do so. You are expected to make an attempt to solve your tasks/problems before posting a question. – Patrick Q Oct 10 '18 at 20:26
  • @PatrickQ Hello friend ... I have followed the examples I found, apparently adding everything correctly in the ajax, but I am very sorry friend, but I do not know what code I should delete in the file index2.php to add to the file ajax.php :( forgive me if I ask wrong, I have only worked with PHP natively, I do not fully understand the use of ajax :( –  Oct 10 '18 at 22:18

3 Answers3

5

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.

Community
  • 1
  • 1
bbenz
  • 129
  • 2
  • 7
  • FWIW, the JavaScript in this answer is ES6, so if you are not transpiling or are supporting older browsers then the string interpolation will not yield the expected result. – JustCarty Oct 16 '18 at 16:47
  • @Timpy Friend. The desired data is all in the index2.php file, that is, I am not using or calling another PHP file. The pagination and the data are shown in the file index2.php everything is in that single file. –  Oct 17 '18 at 04:06
  • @Timpy I'm sorry to confess it. But I do not understand, in my code there is the option to show 10, 25, 50 and 100 rows through the select option in this way and it would lose its validity ... I want to cry I do not understand ... all the PHP code is passed to the ajax file .php but in the json_encode only prints data from the database and the other configurations as the option to show more rows. –  Oct 17 '18 at 04:11
  • @Kary Sorry for not being more clear. On line 46 of your index2.php snippet you're querying your database with this statement: `$stmt = $con->prepare($sql);`. That's the data I was talking about. I'll update my answer to use that data. – bbenz Oct 17 '18 at 11:12
  • @Timpy in this way it shows me data `$result = $con->query($sql); $data_rows = array(); while ($row = $result->fetch_assoc()) { $data_rows[] = $row; }` –  Oct 17 '18 at 21:55
  • @Timpy but errors appear, because of these variables $ localization_sql, $ records_by_page "; I have copied the code as you have stated, but I still do not understand if this is the way it is in your answer that should be left or what code should be added in the ajax file .php of the index2.php file –  Oct 17 '18 at 21:59
  • @Timpy in the index file it does not show me the data instead of the data it shows me undefined undefined undefined –  Oct 17 '18 at 22:01
  • @Timpy I thought it would be easier to use ajax, I have such a nice design but my ambition to make it more pleasant seems to be unreachable –  Oct 17 '18 at 22:20
  • @Kary I added more code to the "Edit" section of my answer. I copied this from your answer. You need to make sure you pass these variables in the ajax url. This is where $records_by_page and $localization_sql are defined. – bbenz Oct 18 '18 at 13:22
  • @Timpy The results now if they are shown, but friend of the soul, I have not given any explanation in your question how it will work, ie the buttons of the page and the select option on showing more or less rows of results 10, 25, 50 and 100. How it should be implemented or how this information will be sent through ajax. –  Oct 19 '18 at 18:27
2

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

msg
  • 7,863
  • 3
  • 14
  • 33
  • Hi @msg Not friend ... I did not mean to say only I want it on one page, just explain that my code is currently running and works in only one file **index2.php.** –  Oct 19 '18 at 18:35
  • I test it now, and it prints me these errors: `Warning: mysqli_stmt::bind_result(): Couldn't fetch mysqli_stmt in index2.php on line 54` -> `$stmt->bind_result($id,$title,$description);` `Warning: mysqli_stmt::fetch(): Couldn't fetch mysqli_stmt in index2.php on line 55` -> `while ($stmt->fetch()) :` `Warning: mysqli_stmt::close(): Couldn't fetch mysqli_stmt in index2.php on line 63` -> `$stmt->close();` I do not understand mistakes, everything seems to be fine. –  Oct 19 '18 at 18:54
  • Friend an efficiency question in this way is the best option or through json is more efficient? –  Oct 19 '18 at 18:57
  • errors are no longer displayed. But I do not see that it has changed much with everything implemented, there is a reload when following the buttons on the page... I thought it would be different, [for example](https://phpzag.com/demo/jquery-bootgrid-server-side-processing-with-php-mysql/) –  Oct 19 '18 at 19:30
  • I have tried to do everything in a native way without using a third-party plugin, and in fact I have achieved it, only missing that little detail of ajax. –  Oct 19 '18 at 19:31
  • Hmm if I have added the javascript script but I did expect it to have been different because it is still as if I were working with my current code –  Oct 19 '18 at 19:40
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/182168/discussion-between-msg-and-kary). – msg Oct 19 '18 at 19:51
-1

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>  
Sven Liivak
  • 1,323
  • 9
  • 10