loretoparisi
loretoparisi

Reputation: 16271

How to paginate an array of results in Javascript

This function can paginate an array of items:

function paginate(res,page,page_size,max_page_size) {
        page=page||1;
        page_size=page_size||10;
        max_page_size=max_page_size||100;
        page_size=page_size>max_page_size?max_page_size:page_size;
        var pages=Math.round( res.length / page_size),
            items=[];
        for( var p=1; p <= pages; p++) {
            var start= Math.round( page_size * (p-1) );
            items.push( res.slice(start,start+page_size) );
        }
        return page < items.length?items[page-1]:items[ items.length-1 ];
    }

having

function paginate(res, page, page_size, max_page_size) {
  page = page || 1;
  page_size = page_size || 10;
  max_page_size = max_page_size || 100;
  page_size = page_size > max_page_size ? max_page_size : page_size;
  var pages = Math.round(res.length / page_size),
    items = [];
  for (var p = 1; p <= pages; p++) {
    var start = Math.round(page_size * (p - 1));
    items.push(res.slice(start, start + page_size));
  }
  return page < items.length ? items[page - 1] : items[items.length - 1];
}

var list = Array.apply(null, Array(10)).map(function() {
  return Array.apply(null, Array(Math.floor(Math.random() * 10 + 3))).map(function() {
    return String.fromCharCode(Math.floor(Math.random() * (123 - 97) + 97));
  }).join('')
});

console.log(list)
for (var i = 1; i < 8; i++) {
  console.log("page", i, paginate(list, i, 2, 2))
}

This function has a bug, since as soon as it reaches the last paginated result, it returns always the same page. Why? Is there an alternative solution?

[UPDATE]

The issue was in the indexes calculation, this is the right version:

 function paginate(res,page,page_size,max_page_size) {
    page=page||1;
    page_size=page_size||10;
    max_page_size=max_page_size||100;
    page_size=page_size>max_page_size?max_page_size:page_size;
    var pages=Math.ceil( res.length / page_size),
        items=[];
    for( var p=1; p <= pages; p++) {
        var start= page_size * (p-1)
        items.push( res.slice(start,start+page_size) );
    }
    return page <= items.length?items[page-1]:[];
}

There were 2 errors: Math.round instead of Math.ceil and the last ternary operator page <= items.length?items[page-1]:[];

Upvotes: 1

Views: 8005

Answers (1)

Shilly
Shilly

Reputation: 8589

Haven't identified the exact issue with your code yet, but I remember struggling alot with keeping state and resetting the index when I reached the end of the array while using rounding functions.

In the end I just made a 'chunker' to divide an array into chunks and hooked that up to something that rendered the array contents using the previous() and next() methods to grab the correct art of the array. Which page it actualy represents in the view, is up to the view to cache.

var Chunker = function Chunker( config ) {
        if ( !Array.isArray( config.data ) ) {
            throw new Error('chunker source is not an array');
            return false;
        }
        this.data = config.data;
        this.index = 0;
        this.length = config.len || config.data.length; // Amount of items per chunk. When not defined, will return the entire array.
    };
Chunker.prototype = {
    'constructor' : Chunker,
    'index' : function index( number ) { // => current index (getter) || => this (setter)
        if ( number !== undefined ) {
            this.index = index;
            return this;
        }
        else return this.index;
    },
    'current' : function current() { // => { "index", "data" }
        return {
            "index" : this.index,
            "data" : this.data.slice( this.index, this.index + this.length )
        };
    },
    'next' : function next() { // => next chunk
        this.index += this.length;
        if ( this.index > this.data.length ) this.index = this.data.length - (this.data.length % this.length);
        return this.current();
    },
    'previous' : function previous() { // => previous chunk
        this.index -= this.length;
        if (this.index < 0 ) this.index = 0;
        return this.current();
    },
    'reset' : function reset() { // => this
        this.index(0);
        return this;
    }
};   

Upvotes: 1

Related Questions