jQuery: impaginare una tabella

jQuery: impaginare una tabella

Impaginare una tabella con jQuery richiede semplicemente l'uso di un contatore per tracciare il numero di righe visualizzate e del metodo slice() per mostrare le righe correnti e nascondere le altre. Possiamo anche associare tali azioni a dei controlli che permetteranno all'utente di navigare tra le pagine in cui è suddivisa la tabella. Vediamo insieme i dettagli dell'implementazione.

La marcatura

La nostra marcatura è composta da due elementi:

  1. I controlli della paginazione
  2. La tabella

La tabella dovrà avere anche gli elementi thead e tbody per facilitare il lavoro sul DOM:


<div class="wrapper-paging">
          <ul>
            <li><a class="paging-back">&lt;</a></li>
            <li><a class="paging-this"><strong>0</strong> di <span>x</span></a></li>
            <li><a class="paging-next">&gt;</a></li>
          </ul>
</div>


<table summary="Elenco di libri sullo sviluppo Web" id="books">
  <thead>
  	....
  </thead>
	<tbody>
	...
	</tbody>
</table>

Il CSS

Gli stili CSS si limitano semplicemente a formattare i controlli della paginazione e la tabella. Per una migliore performance, i controlli verranno inizialmente nascosti in modo da permettere a jQuery di ultimare prima la paginazione della tabella:


.wrapper-paging {
	display: none;
	padding-left: 20px;
	width: 500px;
	text-align: center;
	padding-bottom: 20px;
	margin: 0 auto;
}

.wrapper-paging ul,
.wrapper-paging li {
	margin: 0;
	padding: 0;
}

.wrapper-paging ul li {
	display: inline;
}

.wrapper-paging ul {
	text-align: center;
	list-style-type: none;
}

.wrapper-paging a {
	border: 2px solid #fff;
	border-radius: 3px;
	display: inline-block;
	color: #015287;
	cursor: pointer;
	margin-right: 3px;
	padding: 3px 7px;
	text-decoration: none;
}

.wrapper-paging .paging-this {
	cursor: default;
	padding: 3px 0;
}

.wrapper-paging a:hover {
	background: #015287;
	color: #FFFFFF;
}

.wrapper-paging .paging-back,
.wrapper-paging .paging-next {
	border-color: #015287;
}

.wrapper-paging .paging-this:hover {
	background: #fff;
	color: #015287;
}

.wrapper-paging .paging-this b {
	font-weight: normal;
}

.wrapper-paging .paging-disabled,
.wrapper-paging .paging-disabled:hover {
	background: #fff;
	border-color: grey;
	color: grey;
	cursor: default;
}

table {
	width: 520px;
	border: 1px solid #ddd;
	border-collapse: collapse;
	margin: 0 auto;
}

th {
	background: #015287;
	color: #fff;
	padding: 6px;
	text-align: left;
}

td {
	border-bottom: 1px solid #ddd;
	padding: 6px;
}

tbody tr:nth-child(even) {
	background: #ddd;
}

caption {
	font-size: 1.2em;
	text-transform: uppercase;
	padding-bottom: 4px;
}

Il codice jQuery

Definiamo una funzione che accetta come parametri la tabella su cui operare e il numero di righe per pagina in cui suddividerla:


function paginateTable(table, pages) {


}

A questo punto dobbiamo definire i riferimenti agli elementi della tabella, soprattutto al numero di righe e al valore effettivo del numero di pagine:


function paginateTable(table, pages) {

	var $table = $(table);
  	var $rows = $('tbody > tr', $table);
  	var numPages = Math.ceil($rows.length / pages) - 1;
  	var current = 0;
  	
  	//...
  	
}

numPages è ottenuto dividendo il numero di elementi tr (si noti bene: all'interno di tbody) per il numero di righe passato come parametro. current è un indice che terrà traccia del numero dei gruppi di pagine.

Ora dobbiamo definire dei riferimenti ai controlli per la navigazione delle pagine:


function paginateTable(table, pages) {

	var $table = $(table);
  	var $rows = $('tbody > tr', $table);
  	var numPages = Math.ceil($rows.length / pages) - 1;
  	var current = 0;
  	
  	var $nav = $('ul', 'div.wrapper-paging');
  	var $back = $nav.find('li:first-child a');
  	var $next = $nav.find('li:last-child a');
  	
  	//...
  	
}

Quindi impostiamo i valori dei controlli:


function paginateTable(table, pages) {

	var $table = $(table);
  	var $rows = $('tbody > tr', $table);
  	var numPages = Math.ceil($rows.length / pages) - 1;
  	var current = 0;
  	
  	var $nav = $('ul', 'div.wrapper-paging');
  	var $back = $nav.find('li:first-child a');
  	var $next = $nav.find('li:last-child a');
  	
  	$nav.find('a.paging-this strong').text(current + 1);
  	$nav.find('a.paging-this span').text(numPages + 1);
  	
  	//...
}

A questo punto dobbiamo effettivamente mostrare solo le righe della pagina corrente:


function paginateTable(table, pages) {

	var $table = $(table);
  	var $rows = $('tbody > tr', $table);
  	var numPages = Math.ceil($rows.length / pages) - 1;
  	var current = 0;
  	
  	var $nav = $('ul', 'div.wrapper-paging');
  	var $back = $nav.find('li:first-child a');
  	var $next = $nav.find('li:last-child a');
  	
  	$nav.find('a.paging-this strong').text(current + 1);
  	$nav.find('a.paging-this span').text(numPages + 1);
  	$back
    	.addClass('paging-disabled')
    	.click(function() {
      		pagination('<');
    	});
  	$next.click(function() {
    		pagination('>');
  		  });
  		  
    $rows
    .hide()
    .slice(0,pages)
    .show();
    
    //...
}

Per prima cosa nascondiamo tutte le righe e quindi mostriamo solo quelle selezionate tramite il metodo slice(), che parte dalla prima riga e ha come limite il numero di righe da visualizzare. La funzione interna pagination() è definita come segue:


function paginateTable(table, pages) {

	var $table = $(table);
  	var $rows = $('tbody > tr', $table);
  	var numPages = Math.ceil($rows.length / pages) - 1;
  	var current = 0;
  	
  	var $nav = $('ul', 'div.wrapper-paging');
  	var $back = $nav.find('li:first-child a');
  	var $next = $nav.find('li:last-child a');
  	
  	$nav.find('a.paging-this strong').text(current + 1);
  	$nav.find('a.paging-this span').text(numPages + 1);
  	$back
    	.addClass('paging-disabled')
    	.click(function() {
      		pagination('<');
    	});
  	$next.click(function() {
    		pagination('>');
  		  });
  		  
    $rows
    .hide()
    .slice(0,pages)
    .show();
    
    var pagination = function (direction) {
    var reveal = function (current){
      $back.removeClass('paging-disabled');
      $next.removeClass('paging-disabled');
      
      $rows
        .hide()
        .slice(current * pages, current * pages + pages)
        .show();
        
      $nav.find('a.paging-this strong').text(current + 1);
    };
    
  	if (direction == '<') { 
      if (current > 1) {
        reveal(current -= 1);
      }
      else if (current == 1) {
        reveal (current -= 1);
        $back.addClass('paging-disabled');
      }
    } else {
      if (current < numPages - 1) {
        reveal(current += 1);
      }
      else if (current == numPages - 1) {
        reveal(current += 1);
        $next.addClass('paging-disabled');
      }
    }
  }



}

La funzione accetta come parametro i segni di maggiore e minore. Il primo indica avanzamento, quindi la variabile current viene incrementata di 1, mentre il secondo indica un passo indietro nelle pagine, quindi l'indice viene decrementato di 1. Allo stesso modo la funzione si accorge di quando si è raggiunto il limite delle pagine disponibili e disabilita il controllo corrente.

Il cuore di questa funzione è costituito dalla funzione reveal(), il cui codice più importante è il seguente:


$rows
        .hide()
        .slice(current * pages, current * pages + pages)
        .show();

Questo codice mostra solo il numero di righe disponibili su ogni pagina. Quindi se current all'inizio è 0 e vogliamo 10 righe per pagina, avremo:


$rows.hide().slice(0 * 10, 0 * 10 + 10).show();

ossia le righe fino a 10. Se current è 1 avremo le righe dalla 10 fino alla 20, e così via. Ovviamente se il valore di current diminuisce torneremo al gruppo di righe precedenti.

Usiamo questo codice come segue:


$(function() {

  $('.wrapper-paging').show();
  paginateTable('#books', 10);
  
});

Potete visionare l'esempio finale in questa pagina.

Torna su