Pagination script not updating number of pages on select change

I have a script that paginates pages in a table, which works fine. I also have a dropdown to select how many records to show in the table. Although this works, if I select say 20 records the pagination does not update to reflect the change.

When the table is run, the default records to show is 8 whih makes 9 pages. But if I select 20 in the drop down it still says 9 and if I go to page 9 it is obviously empty. I am also wondering if it is possible to have the script appear in both before and after the table. the reson for this is if a user gets to the bottom of say 100 records, then I would like this feature so they don’t have to go all the way back to the top.

I would appreciate any help as my javascript is not 100%. Many thanks

PS: From what i can gather, i have to re-rendering the inside the repaginate() function. Keep the<div class="pager"> where it is but move the bit that renders the actual pages inside the repaginate() function. Tried various options but not working. Any idea how I can do this as I am really struggling with it. Thanks

<?php
    echo "<table class='paginated' cellspacing='0' cellpadding='0'>";
    echo "<div class='pager'></div>";
    echo "<thead><tr><th style='width: 5%;'>#</th><th>Service</th><th>Activity</th><th>Dept</th><th>Company</th><th>Address</th><th>User</th><th>Item</th><th>Date</th><th style='width: 19%;'>Action</th></tr></thead>";

    while($row = mysqli_fetch_array($result)){

    $id = $row['id'];
    $service = $row['service'];
    $activity = $row['activity'];
    $dept = $row['department'];
    $company = $row['company'];
    $address = $row['address'];
    $user = $row['user'];
    $box = $row['item'];
    $date = $row['date'];
    $date = date('d-m-Y h:i:s', strtotime($date));
    $edit = "<button type='button' class='btn btn-primary edit'>Edit</button>";
    $action = "<button type='button' class='btn btn-success action'>Action</button>";
    $delete = "<button type='button' class='btn btn-danger delete'>Delete</button>";

    // each looped row

    echo "<tr><td>".$id."</td><td>".$service."</td><td>".$activity."</td><td>".$dept."</td><td>".$company."</td><td>".$address."</td><td>".$user."</td><td>".$box."</td><td>".$date."</td><td>".$edit. ' ' .$action. ' ' .$delete."</td></tr>";

    } // End while loop
    echo "</table><br /><br /></div>";
?>

javascript

$(function() {
$('table.paginated').each(function() {
  var currentPage = 0;
  var numPerPage = 8;
  var $table = $(this);
  $table.bind('repaginate', function() {
    $table.find('tbody tr').hide().slice(currentPage * numPerPage, (currentPage + 1) * numPerPage).show();
  });
  $table.trigger('repaginate');
  var numRows = $table.find('tbody tr').length;
  var numPages = Math.ceil(numRows / numPerPage);
  var $pager = $('<div class="pager"></div>');
  for (var page = 0; page < numPages; page++) {
    $('<span class="page-number"></span>').text(page + 1).bind('click', {
      newPage: page
    }, function(event) {
      currentPage = event.data['newPage'];
      $table.trigger('repaginate');
      $(this).addClass('active').siblings().removeClass('active');
    }).appendTo($pager).addClass('clickable');
  }
  $pager.insertBefore($table).find('span.page-number:first').addClass('active');
  var $numberPicker = $('<div class="numberPicker"></div>');
  var dropdown = $('<select class="options"></select>');
  $([5, 10, 20]).each(function() {
    var $num = this;
    $('<option></option>').text(this).attr('value', this).appendTo(dropdown);
  });
  dropdown.bind('change', function() {
    numPerPage = this.value;
    $table.trigger('repaginate');
  }).insertAfter($table);
});
});

I’m gonna go ahead and guess that the first problem is you dont have a tbody tag in your table.

1 Like

Good spot. Unfortunately hasn’t made any difference. Still not updating number of pages on dropdown selection. Thanks

Oh sorry, my brain didnt actually read all of the OP because i’m a derp. Forgive me.
The code as listed doesnt actually have anything to renumerate the pages, but it should be easy enough to do… i’d wrap the for block on line 13 of the javascript into a function, something like ‘drawpages’. Take the numPages calculation with it. Call it on line 13 (so it still does the initial setup), and then also call it in the dropdown trigger, after expunging the current elements with a .remove()…

  function drawpages() {
   var numPages = Math.ceil(numRows / numPerPage); 
    for (var page = 0; page < numPages; page++) {
    //...
    }
  }
  drawpages();
  //...
  dropdown.bind('change', function() {
    numPerPage = this.value;
    $('.page-number').remove();
    drawpages();
    //...

(You may also want to add some logic to change the current page number to the appropriate page.)

1 Like

Just in the interests of practising for fun I had a go at this and the result is below.

I was mainly concerned in getting something to work firstly and the next step would be to tidy up the code as frankly its a bit of a mess :slight_smile:. I’m sure one of the JS experts here could tidy it up considerably or indeed offer a better method to do the pagination?

1 Like

Thanks very much. Works a treat. Just one thing. When the page first loads, the dropdown is above the number of pages. However, when you select an option, it drops below the number of pages. Is this an easy fix. Also, would it be possible to have the dropdown the same as the pages top and bottom. Many Thanks

Just insert the drop down after the second pager.

e.g.

}).insertAfter($pager2);

Codepen updated:

Hi paul
Thanks for that. BTW is it possible to have the options above as well as below. Many thanks for your help.

I’ve adjusted the codepen again and added the dropdown above. It all seems to work but seems messy and has duplication in places.

It could do with one of the experts here (like @James_Hibbard or @Paul_Wilkins ) to tidy it up and refine (or refactor) :slight_smile:

Hey Paul, sure thing. I’m in the middle of reinstalling my OS right now, so won’t be around for a couple of days, but I’ll check back in when I’m done and would be glad to have a look at the code :slight_smile:

1 Like

Hi Paul. Your code works fine. I haven’t checked for dupes but shall check back when Pullo has give it the once over. Thanks very much.

Hi,

I had a look at your code, Paul and the thing I missed most was some kind of control flow — i.e. I wasn’t really able to read the code and have an idea of what was happening where. This means that when you revisit it in a few months, nor will you :slight_smile:

To that end, I rewrote things a little. You’ll notice I’m making use of ES6.

function makeDropdown({ dropdownValues }) {
  return `
    <select class='paginationDropdown'>
      ${dropdownValues.map(val => `<option value='${val}'>${val}</option>`)}
    </select>
  `;
}

function makePaginationControls({ numRows, selectedDropdownValue }) {
  const numControls = Math.ceil(numRows / selectedDropdownValue);
  return `
    <div class='pager'>
      ${[...Array(numControls)].map((_, i) => `<span class="page-number clickable">${i + 1}</span>`).join('')}
    </div>
  `;
}

function buildTable({ selectedPagerValue, selectedDropdownValue, table }) {
  const from = (selectedPagerValue - 1) * selectedDropdownValue;
  const to = selectedDropdownValue * selectedPagerValue;

  return table
    .clone(true)
    .find('tbody tr')
    .filter(i => i >= from && i < to);
}

function addPagination(i, table) {
  const s = {
    dropdownValues: [5, 10, 15, 20],
    selectedDropdownValue: 5,
    selectedPagerValue: 1,
    numRows: $(table).find('tbody tr').length,
    table: $(table).clone(true),
  };

  $('body').append(makeDropdown(s));
  $('body').append(makePaginationControls(s));

  $('select.paginationDropdown').on('change', function dropdownChange() {
    s.selectedDropdownValue = Number(this.value);
    s.selectedPagerValue = 1;
    $('.pager').remove();
    $('body').append(makePaginationControls(s));
    $(table).find('tbody').html(buildTable(s));
  });

  $(document).on('click', '.clickable', function paginationClick() {
    s.selectedPagerValue = Number(this.textContent);
    $(table).find('tbody').html(buildTable(s));
  });

  $('select.paginationDropdown').trigger('change');
}

$('table.paginated').each(addPagination);

It still needs some tweaking and is not as feature complete as your version, but hopeflly the rest shouldn’t be too hard to add back in. I would also consider adding a query string to the pagination links in case the user wants to link to a section of the table.

As a final thought, if JS isn’t really the OP’s bag, it might be an idea to look at one of the plugins out there that does this kind of thing for you.

1 Like

Thanks @James_Hibbard that’s very useful and I will work my way through it and try to improve the way I code js. I do tend to just try and make things work first and does often seem like magic later on :slight_smile:

I believe the OP has moved on now with more help in the JS forum but for learning purposes the revision will be very useful. :slight_smile:

No worries Paul, I was just having a look at this now and have made a couple of tweaks so that it works with multiple tables and adds an active class to the current pagination link.

function makeDropdown({ dropdownValues }) {
  return `
    <select class='paginationDropdown'>
      ${dropdownValues.map(val => `<option value='${val}'>${val}</option>`)}
    </select>
  `;
}

function makePaginationControls({ numRows, selectedDropdownValue }) {
  const numControls = Math.ceil(numRows / selectedDropdownValue);
  return `
    <div class='pager'>
      ${[...Array(numControls)].map((_, i) => `<span class="page-number clickable ${i === 0 ? 'active' : ''}">${i + 1}</span>`).join('')}
    </div>
  `;
}

function buildTable({ selectedPagerValue, selectedDropdownValue, table }) {
  const from = (selectedPagerValue - 1) * selectedDropdownValue;
  const to = selectedDropdownValue * selectedPagerValue;

  return table
    .clone(true)
    .find('tbody tr')
    .filter(i => i >= from && i < to);
}

function addPagination(i, table) {
  const s = {
    dropdownValues: [5, 10, 15, 20],
    selectedDropdownValue: 5,
    selectedPagerValue: 1,
    numRows: $(table).find('tbody tr').length,
    table: $(table).clone(true),
  };

  $(table).append(makeDropdown(s));
  $(table).append(makePaginationControls(s));

  $(table).find('select.paginationDropdown').on('change', function dropdownChange() {
    s.selectedDropdownValue = Number(this.value);
    s.selectedPagerValue = 1;
    $(table).find('.pager').remove();
    $(table).append(makePaginationControls(s));
    $(table).find('tbody').html(buildTable(s));
  });

  $(table).on('click', '.clickable', function paginationClick() {
    s.selectedPagerValue = Number(this.textContent);
    $(this).siblings().removeClass('active');
    $(this).addClass('active');
    $(table).find('tbody').html(buildTable(s));
  });

  $(table).find('select.paginationDropdown').trigger('change');
}

$('table.paginated').each(addPagination);

I hear ya, but I got bitten by that so often, that regardless of how messy the rest of the code is, I always try to have some kind of structure that one can follow to have a rough idea of what is going on where. Even if it’s just:

$(() => {
  function do_this() { ... }
  function do_that() { ... }
  function the_other() { ... }

  do_this()
  do_that()
  do_the_other()
});
1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.