Code Monkey home page Code Monkey logo

backbone.paginator's Introduction

backbone.paginator

ci-status_ cdnjs-version_

A pageable, drop-in replacement for Backbone.Collection called Backbone.PageableCollection.

Table of Contents

Migrating from Backbone.Paginator 1.0

Backbone.Paginator 2.0 was originally called backbone-pageable, which in turn was inspired by Backbone.Paginator < 1.0 by @addyosmani. The two projects have merged as of May 2014 and backbone-pageable has effectively become Backbone.Paginator 2.0. This guide describes some of the differences and similarities to ease migration.

Package Naming

Backbone.Paginator 2.0 will continue to use the backbone.paginator name for the file, npm and bower packages. In addition, a new component package is also available, also inheriting the backbone.paginator name.

Module Naming

The module exported by the packages will still be called PageableCollection to emphasize the function of this Backbone plugin as a Collection instead of a View.

API Changes

Backbone.Paginator <= 1.0 Backbone.Paginator 2.0
Backbone.Paginator Backbone.PageableCollection
Backbone.Paginator.requestPager PageableCollection.extend({mode: "server" | "infinite"})
Backbone.Paginator.clientPager PageableCollection.extend({mode: "client"})
paginator_core Override PageableCollection#sync
paginator_ui state
server_api queryParams
bootstrap() new Backbone.PageableCollection([{...}, ...])
parse() parse(), parseRecords(), parseState(), parseLinks()
goTo() getPage()
prevPage(), nextPage() getPreviousPage(), getNextPage()
howManyPer() setPageSize()
setSort() setSorting()
*Filter*() N/A. Implement your own View or use underscore methods on fullCollection
Diacritic plugin N/A. See above
N/A getPageByOffSet()
N/A hasPreviousPage(), hasNextPage()
N/A switchMode()

Advantages

Supports client-side and server-side operations

You can initialize Backbone.PageableCollection to paginate and/or sort on the client-side, server-side or both.

Infinite paging

Many public APIs like Github or Facebook support infinite paging, Backbone.PageableCollection can handle them easily.

Comes with reasonable defaults

Server API parameters preconfigured to work with most Rails RESTful APIs by default.

Works well with existing server-side APIs

Query parameter mappings are all configurable, and you can use either 0-based or 1-based indices.

Bi-directional event handling

In client-mode, any changes done on one page is immediately reflected on the others with the appropriate events propagated.

100% compatible with existing code

Backbone.PageableCollection is a strict superset of Backbone.Collection and passes its test suite.

Well tested

Comes with 100s of tests in addition to the Backbone.Collection test suite.

Well documented

Use cases and functionality are thoroughly documented.

No surprising behavior

Backbone.PageableCollection performs internal state sanity checks at appropriate times, so it is next to impossible to get into a weird state.

Light-weight

The library is only 4.1KB minified and gzipped.

Playable Demos

The following examples utilizes Backgrid.js to render the collections.

Installation

Installing from Component

component install backbone.paginator

Installing from Node.js

npm install backbone.paginator

Installing from Bower

bower install backbone.paginator

Browser

<script src="underscore.js"></script>
<script src="backbone.js"></script>
<script src="backbone.paginator.js"></script>

Getting to the Backbone.PageableCollection Class from Node.js and AMD

var PageableCollection = require("backbone.paginator");

Getting to the Backbone.PageableCollection Class in the Browser

var PageableCollection = Backbone.PageableCollection;

Introduction

Like Backbone.Collection, you can provide a URL endpoint, configure your initial pagination state and server API mapping by extending Backbone.PageableCollection:

var Book = Backbone.Model.extend({});

var Books = Backbone.PageableCollection.extend({
  model: Book,
  url: "api.mybookstore.com/books",

  // Any `state` or `queryParam` you override in a subclass will be merged with
  // the defaults in `Backbone.PageableCollection` 's prototype.
  state: {

    // You can use 0-based or 1-based indices, the default is 1-based.
    // You can set to 0-based by setting ``firstPage`` to 0.
    firstPage: 0,

    // Set this to the initial page index if different from `firstPage`. Can
    // also be 0-based or 1-based.
    currentPage: 2,

    // Required under server-mode
    totalRecords: 200
  },

  // You can configure the mapping from a `Backbone.PageableCollection#state`
  // key to the query string parameters accepted by your server API.
  queryParams: {

    // `Backbone.PageableCollection#queryParams` converts to ruby's
    // will_paginate keys by default.
    currentPage: "current_page",
    pageSize: "page_size"
  }
});

You can initialize state and queryParams from the constructor too:

var Books = Backbone.PageableCollection.extend({
  model: Book,
  url:"api.mybookstore.com/books"
});

var books = new Books([], {

  // All the `state` and `queryParams` key value pairs are merged with
  // the defaults too.
  state: {
    firstPage: 0,
    currentPage: 0
  },

  queryParams: {
    currentPage: "current_page",
    pageSize: "page_size"
  }
});

Adapting to a Server API

To adapt to an existing server API that do not use will_paginate keys, you can configure the queryParams object hash to map state keys to the query parameters your server will accept. Those query parameters will be in the query string of the URL used for fetching. You can also put extra items into queryParams and they will be in the query string as is. Setting null as the value of any mapping will remove it from the query string. Finally, the values in the queryParams can be either a literal value or a parameter-less function that returns a value.

This is a listing of the default state and queryParam values.

state queryParams
Attribute Value Attribute Value

============ ===== firstPage 1 lastPage null

============= ============================

currentPage null currentPage "page"
pageSize 25 pageSize "per_page"
totalPages null totalPages "total_pages"
totalRecords null totalRecords "total_entries"
sortKey null sortKey "sort_by"
order -1 order "order"
directions { "-1": "asc", "1": "desc" }

You can consult the API documentation for a detailed explanation of these fields.

Fetching Data and Managing States

You can access the pageable collection's internal state by looking at the state object attached to it. This state object, however, is generally read-only after initialization. There are various methods to help you manage this state, you should use them instead of manually modifying it. For the unusual circumstances where you need to modify the state object directly, a sanity check will be performed at the next time you perform any pagination-specific operations to ensure internal state consistency.

Method Use When
setPageSize Changing the page size
setSorting Changing the sorting
switchMode Switching between modes
state Need to read the internal state
get*Page Need to go to a different page
hasPreviousPage, hasNextPage Check if paging backward or forward is possible

In addition to the above methods, you can also synchronize the state with the server during a fetch. Backbone.PageableCollection overrides the default Backbone.Collection#parse method to support an additional response data structure that contains an object hash of pagination state. The following is a table of the response data structure formats Backbone.PageableCollection accepts.

In your UI code, you can listen to the pageable:state:change event on the pageable collection to receive state updates.

Without State With State
[{}, {}, ...] [{ pagination state }, [{}, {} ...]]

Most of the time, providing something like this in your response is sufficient for updating the pagination state.

[{"total_entries": 100}, [{}, {}, ...]]

Since 1.1.7, customizing parse has been simplified and the default implementation now delegates to two new methods - parseState and parseRecords. You are encouraged to override them instead of parse if it is not clear how to do so. For infinite mode, you should override parseLinks instead of parseState to return an object of links.

See the examples below or the API for details on customizing parseState, parseRecords and parseLinks.

Bootstrapping

Backbone.PageableCollection is 100% compatible with Backbone.Collection 's interface, so you can bootstrap the models and supply a comparator to the constructor just like you are used to:

// Bootstrap with just 1 page of data for server-mode, or all the pages for
// client-mode.
var books = new Books([
  { name: "A Tale of Two Cities" },
  { name: "Lord of the Rings" },
  // ...
], {
  // Paginate and sort on the client side, default is `server`.
  mode: "client",
  // This will maintain the current page in the order the comparator defined
  // on the client-side, regardless of modes.
  comparator: function (model) { return model.get("name"); }
});

Pagination

Server-Mode

Backbone.Pagination defaults to server-mode, which means it only holds one page of data at a time. All of the get*page operations are done by delegating to fetch. They return a jqXHR in this mode.

books.getFirstPage();
books.getPreviousPage();
books.getNextPage();
books.getLastPage();

// All the `get*Page` methods under server-mode delegates to `fetch`, so you
// can attach a callback to the returned `jqXHR` objects' `done` event.
books.getPage(2).done(function () {
  // do something ...
});

All of the get*Page methods accept the same options Backbone.Collection#fetch accepts under server-mode.

Client-Mode

Client-mode is a very convenient mode for paginating a handful of pages entirely on the client side without going through the network page-by-page. This mode is best suited if you only have a small number of pages so sending all of the data to the client is not too time-consuming.

var books = new Books([
  // Bootstrap all the records for all the pages here
], { mode: "client" });

All of the get*Page methods reset the pageable collection's data to the models belonging to the current page and return the collection itself instead of a jqXHR.

// You can immediately operate on the collection without waiting for jQuery to
// call your `done` callback.
var json = JSON.stringify(books.getLastPage());

// You can force a fetch in client-mode to get the most updated data if the
// collection has gone stale.
books.getFirstPage({ fetch: true });

// Do something interesting with books...

Infinite-Mode

Infinite paging mode is a hybrid of server mode and client mode. Once initialized and bootstrapped, paging backwards will be done on the client-side by default while paging forward will be done by fetching.

As before, you can make use of getFirstPage, getPreviousPage, getNextPage, and getLastPage for navigation under infinite-mode. If a page has been fetched, you can use getPage directly with the page number, an error will be thrown if the page has not been fetched yet.

By default, Backbone.PageableCollection parses the response headers to find out what the first, next and prev links are. The parsed links are available in the links field.

var Issues = Backbone.PageableCollection.extend({
  url: "https://api.github.com/repos/documentclound/backbone/issues?state=closed",
  mode: "infinite",

  // Initial pagination states
  state: {
    pageSize: 15,
    sortKey: "updated",
    order: 1
  },

  // You can remap the query parameters from ``state`` keys from the default
  // to those your server supports. Setting ``null`` on queryParams removed them
  // from being appended to the request URLs.
  queryParams: {
    totalPages: null,
    totalRecords: null,
    sortKey: "sort",
    order: "direction",
    directions: {
      "-1": "asc",
      "1": "desc"
    }
  }

});

var issues = new Issues();

issues.getFirstPage().done(function () {
   // do something interesting...
});

If your server API does not return the links using the Link header like Github does, you can subclass Backbone.PageableCollection to override the parseLinks methods to return a links object.

var FBComment = Backbone.Model.extend({});

var FBComments = Backbone.PageableCollection.extend({
  model: FBComment,
  url: "https://graph.facebook.com/A_REALLY_LONG_FACEBOOK_OBJECT_ID",
  mode: "infinite",
  // Set the indices to 0-based for Graph API.
  state: {
    firstPage: 0
  },
  queryParams: {
    pageSize: "limit",
    // Setting a parameter mapping value to null removes it from the query string
    currentPage: null,
    // Any extra query string parameters are sent as is, values can be functions,
    // which will be bound to the pageable collection instance temporarily
    // when called.
    offset: function () { return this.state.currentPage * this.state.pageSize; }
  },
  // Return all the comments for this Facebook object
  parseRecords: function (resp) {
    return resp.comments.data;
  },
  // Facebook's `paging` object is in the exact format
  // `Backbone.PageableCollection` accepts.
  parseLinks: function (resp, xhr) {
    return resp.comments.paging;
  }
});

To act on the newly fetched models under infinite mode, you can listen to the fullCollection reference's add event like you would under client mode, and render the newly fetched models accordingly.

var ToiletPaper = Backbone.View.extend({

  events: {
    "scroll": "fetchSheets"
  },

  initialize: function (options) {
    this.listenTo(this.collection.fullCollection, "add", this.addSheet);
  },

  addSheet: function () {
    // ...
  },

  fetchSheets: function () {
    this.collection.getNextPage();
  },

  // ...

});

var wordsOfTheDay = new Backbone.PageableCollection({
  mode: "infinite",
  // url, initial state, etc...
});

var toiletPaper = new ToiletPaper({collection: wordsOfTheDay});

$("#toilet-paper-dispenser").append(toiletPaper.render().el);

wordsOfTheDay.fetch();

Note:

Don't override parseState or send down a stateful list of records from the server.

Under infinite mode, totalRecords will always equal to the number of models inside fullCollection i.e. fullCollection.length. PagebleCollection will automatically keep all the states consistent. Modifying the state during infinite paging results in undefined behavior. As such, you shouldn't override parseState and should only send down a stateless list of records as described in Fetching Data and Managing States.

Sorting

Sorting has been drastically simplified in the 1.0 release while retaining the full power it had in older versions.

The main way to define a sorting for a pageable collection is to utilize the setSorting method. Given a sortKey and an order, setSorting sets state.sortKey and state.order to the given values. If order is not given, state.order is assumed. By default a comparator is applied to the full collection under client mode. Calling sort on the full collection will then get the entire pageable collection sorted globally. When operating under server or infinite mode, no comparator will be applied to the collection as sorting is assumed to be done on the server by default. Set options.full to false to apply a comparator to the current page under any mode. To sort a pageable collection under infinite mode on the client side, set options.side to "client" will apply a comparator to the full collection.

Setting sortKey to null removes the comparator from both the current page and the full collection.

var books = new Books([
  ...
], {
  mode: "client"
});

// Sets a comparator on `#fullCollection` that sorts the title in ascending
// order
books.setSorting("title");

// Don't forget to call `sort` just like you would on a `Backbone.Collection`
books.fullCollection.sort();

// Clears the comparator
books.setSorting(null);

// Sets a comparator on the current page that sorts the title in descending
// order
books.setSorting("title", 1, {full: false})
books.sort();

books.switchMode("infinite");

// Sorts the books collection under infinite paging mode on the client side
books.setSorting("title", -1, {side: "client"});
books.fullCollection.sort();

books.switchMode("server");

// Sets a comparator on the current page under server mode
books.setSorting("title", {side: "client", full: false});
books.sort();

Manipulation

This is one of the areas where Backbone.PageableCollection truly shines. A Backbone.PageableCollection instance not only can do everything a plain Backbone.Collection can for the current page, in client-mode, it can also synchronize changes and events across all of the pages. For example, you can add or remove a model from either a Backbone.PageableCollection instance, which is holding the current page, or the Backbone.PageableCollection#fullCollection collection, which is a plain Backbone.Collection holding the models for all of the pages, and the pages will all update themselves to maintain within a page size. Any additions, removals, resets, model attribute changes and synchronization actions are communicated between all the pages throughout the two collections.

// The books collection is initialized to start at the first page.
var books = new Books([
  // bootstrap with all of the models for all of the pages here
], {
  mode: "client"
});

// A book is added to the end of the current page, which will overflow to the
// next page and trigger an `add` event on `fullCollection`.
books.push({ name: "The Great Gatsby"});

books.fullCollection.at(books.state.currentPage - 1 * books.state.pageSize).get("name");
>>> "The Great Gatsby"

// Add a new book to the beginning of the first page.
books.fullCollection.unshift({ name: "Oliver Twist" });
books.at(0).get("name");
>>> "Oliver Twist"

API Reference

See here.

FAQ

  1. Which package managers does backbone.paginator support?

    bower, npm, CommonJS and AMD and Component.

  2. Why doesn't backbone.paginator support filtering?

    Wheels should be reinvented only when they are crooked. backbone.paginator aims to do one thing only and does it well, which is pagination and sorting. Besides, since Backbone.PageableCollection is 100% compatible with Backbone.Collection, you can do filtering fairly easily with Backbone's built-in support for Underscore.js methods.

Copyright (c) 2012-2014 Jimmy Yuen Ho Wong and contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

backbone.paginator's People

Contributors

achinaou avatar bazineta avatar bryanbuchs avatar dan-f avatar daspilker avatar ehteshamkafeel avatar extend1994 avatar greenkeeperio-bot avatar josx avatar kahwee avatar leoc avatar liorcode avatar master-contributor avatar moricard avatar ogonkov avatar seanhussey avatar sharifmamun avatar tgriesser avatar tirkarthi avatar vrinek avatar wyuenho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

backbone.paginator's Issues

populating collection using simple list fetched from backend controller

Hi,
I need to use my own format returned data instead of netflix api.
Can you please explain how to populate collection when response is in simple Arraylist?
in simple backbone example I am doing this like below code

var sModel = Backbone.Model.extend({
urlRoot : "/display/showdata",
//to specify default attributes for model
defaults: {
//attrName : default value
"id" : "",
"name" : "",
"Number" : "",
"type" : ""
}
});

var DataCollection = Backbone.Collection.extend({
model:sModel,
url:""/display/showdata"
});

Bug after fetch: clientPager collection isn't updated (only first time it is updated)

I think there is a bug in clientRequest.pager() method, the interesting lines are 180-187:

// Saving the original models collection is important // as we could need to sort or filter, and we don't want // to loose the data we fetched from the server. if (self.origModels === undefined) { self.origModels = self.models; } self.models = self.origModels;

If i fetch for the first time, that's fine.
Let's assume that the length of collection is 26. If i fetch for second time with different parameters, such as the elements (self.origModels) returned by server are 2, with the instruction self.models = self.origModels; they remain 26, while i expect that they become 2.

I'm partially resolving with instructions
if ( clientRequestColl.origModels!==undefined ){ clientRequestColl.origModels=resp } in success callback of fetch, where resp is the result (array) returned by the server (the second time it has length 2).
But in this way the third time that i fetch elements i meet another error in backbone.js, like this "Object # has no method 'off'". (tomorrow i will try to resolve this too)

What do you think? IS this a bug? Or am i misunderstanding about the behaviour of clientRequest?

[Request] Filter by string

I'm not really sure if that's Pagers work, but since we have a sort option, it would be useful to have a "filter" option too. That means, passing a string to a filter function, so the filter "hides" temporaly the items that don't match that string.

For example, having a collection with colors [green, red, blue, orange, white, black] and passing the string "re" will filter the collection to [gREen, REd].

Regards!

goTo with out of bounds page must have a consistent behavior

When executing goTo in clientPager with a page number which is out of bounds (1 <= page <= totalPages), clientPager tries to navigate to it and we get 0 records and currentPage = page number.

I would expect that (1) it will thrown an exception or (2) will navigate to the default page (paginator_ui.firstPage).

I tend to prefer option (2). I will create a pull request for that.

Able to page in to negative pages

I've found that if one was to rapidly fire the requestPreviousPage event on a requestPager, it will no stop you from going in to negative pages. I can't use the curentPage attribute as a guard (unless I'm doing something wrong), because the currentPage attribute waits until the request finishes to update.

Any ideas?

url as function fails

Great plugin, thanks for the effort!

I noticed that specifying a function as the url property results in the function source as the url.

In Paginator.clientPager.sync and Paginator.requestPager.sync:

url: this.url,

Could be:

url: _.isFunction(this.url) ? this.url() : this.url,

Thanks,
Tim

[Request] Scroll-based infinite paging

A pseudo-infinite loading already exist with "Show More" on http://addyosmani.github.com/backbone.paginator/examples/netflix-infinite-paging/index.html. It would be nice to have a scroll-based infinite loading where next page's content are fetched and loading when scrolling reaches near the bottom of the page.

Similar to http://backbonetutorials.com/infinite-scrolling/ (demo: http://backbonetutorials.com/examples/infinite-scroll/), but the source code is available for download: https://github.com/thomasdavis/backbonetutorials/zipball/gh-pages. A collection already exist here: https://github.com/joneath/infiniScroll.js/blob/master/lib/infiniScroll.js that is open sourced under MIT license. Is there a way to apply infiniScroll.js to Backbone Paginator in its current state?

It would be great to be able to apply infinite scrolling to a div or body and be able to have multiple instances on the same page. The body needs CSS of overflow:scroll; and maybe even fixed/specified height. More info: http://stackoverflow.com/questions/7634529/backbone-js-detecting-scroll-event.

Release version 0.5

@alexandernst It's been a while since we did a formal release. Let's do one soon :) If we can nail down the unit tests, I'm happy to put together the changelog and help with docs updates where needed.

Paginator.requestPager() - info() returning 'totalRecords'

Most of the server side pagination returns the records based out of these 2 inputs "currentPage" and also "resultsPerPage"(perPage), returning actual records and also "totalRecords".

If we look at "netflix-request-paging" example it returns "totalCount" as "__count". It is a good idea to let "info()" method return this "totalCount" so that UI will have access to it if needed.

Currently i have modified "backbone.paginator.js" to use like this:

backbone.paginator.js


info: function () {

            var info = {
                currentPage: this.currentPage,
                firstPage: this.firstPage,
                totalPages: this.totalPages,
                lastPage: this.totalPages,
                perPage: this.perPage,
                totalCount: this.totalCount
            };

            this.information = info;
            return info;
        },

paginatedCollection.js


        parse: function (response) {
            // Be sure to change this based on how your results
            // are structured (e.g d.results is Netflix specific)
            var tags = response.d.results;
            //Normally this.totalPages would equal response.d.__count
            //but as this particular NetFlix request only returns a
            //total count of items for the search, we divide.
            this.totalPages = Math.floor(response.d.__count / this.perPage);
            this.totalCount = parseInt(response.d.__count);
            return tags;
        }

Updating server_api attributes

Hello,

I've just updated to your latest version and have an issue with updating some of the parameters to re-render.

I have a search field and before inside my view, i would do this.collection.query = 'some query' then I would call this.collection.page().

However, this doesn't seem to work anymore. Any suggestions how to update attributes and re-post/re-render?

Thank you!

Discussion

Thanks for taking a lead on this. A backbone pagination plug-in is on my wish list for a long time :).
With that said: The current sort implementation doesn't look right to me.
It works on the result set returned from server. For larger result sets (complete A-Z) this is most of the time only a subset (say returned only A to mid B)..
Instead sort should be either done server side or if sorting is not available on the server a) not done at all or b) only if the complete result set is transferred.
If done server side if a new sort order is requested it should reset pagination and return to page set 1.

Rainer

server_api functions not returning anything or being applied

  1. I am using Zepto.js, so all I did was change the last line of pagination script to:
   return Paginator;
}( Backbone, _, Zepto ));
  1. I set the server_api object with the following values.
server_api: {
  'param1' : 'hello', // this works
  'param2' : 4,  // this works
  'param3' : function() { return 6;}, // nope
  'count': function(){ return this.perPage }, //nope 
  'page' : function(){ return this.currentPage }, //nope
},

The request URL ends up as is below. How come 3rd, 4th, and 5th, parameters are not being returned?
http://www.website.com/?json=get_recent_posts&param1=hello&param2=4

Release tasks

I think it might be a good idea to do a new release soon as we've had a number of changes to the paginator lately. I've put together a wiki page of the high-level changes here:

https://github.com/addyosmani/backbone.paginator/wiki/Changelog

Other tasks that we might want to consider before the next release:

  • Docs
  • UI testing
  • Unit Tests? I know we definitely want them but the question is whether to hold off on a release until these are ready

What are your thoughts on the above @alexandernst?

Changing url of collection gives erroneous fetch

Hi, I change the url of my collection dynamically to interface with my API (slim) but whenever I change the URL of the collection to something other than the default (api/models/) the model.fetch is never successful.

Am I doing something wrong or is this a bug?

searchModels:function()
{
var letters = $("#searchText").val();//Get search string

    if(letters != "")//If search string is not null, do the search with custom url
    {
        this.model.url = "api/models/search/" + letters;
        var self = this;
        this.model.fetch({
            success:function() {
                self.model.pager();
            }
        });
    }
    else//The search string is empty so we just default to the regular search(returns all records)
    {
        this.model.url = "api/models";
        var self = this;
        this.model.fetch({
            success:function() {
                self.model.pager();
            }
        });
    }
},

sync event

Hi,

If this requestPager is extended from a Collection why doesn't if fire the sync event? I'd like to use this event to handle collection processing once a page of results comes in.

Drew

bootstrapping requestPager

For those wanting to do progressive enhancement, when the page initially loads, we already have the models loaded as part of the initial page load (without executing any JS). In this case, we attach our JS hooks to the page for enabling progressive enhancement. In such cases, we would not like to trigger the sync (fetch) to bootstrap paginator...requestNextPage etc only work if the initial sync has happened because some of the bootstrap code is in the sync function of the requestPager. Is there any way you could move this to the initialize function?

Filter values

While working on the project at work on which I'm using this library I thought that some kind of required-filter option could be really useful.
I mean, we already have the setSort() and setFilter() methods. setSort() will, as it's name says, set the sort order. The setFilter() method will filter by a search string (query).
But what if we add a .setFieldsFilter() that will force each attribute of a model to match some kind of rule.

I mean,

my_books_collection.setFieldsFilter({ field:publish_year, type:range, value:[1995-1998]});

So that will filter the collection to book which were published only between 1995 and 1998.
Other types could be required (not empty), accepted, min, max, range, minLength, maxLength, rangeLength, oneOf, equalTo, parrern and function.
(The idea for all those came from a project of yours called backbone.validation :p)

What do you think?
I need that for the project I'm working at work, so I could implement that really quickly.

Making 'url as function' more useful

In Backbone.Collection when the 'url' is used as function, we can bind the this to the function and access the member variables while generating the url. This comes handy in many cases especially while following Rails URLs style like http://example.com/product/show/1

But in the case of backbone.paginator since the url() is executed after var queryOptions = _.clone(self.paginator_core);, we cannot bind and access any of member variables of the collection.

Is there a possibility to have url: _.result(queryOptions, 'url') run before the paginator_core is cloned?

Or is there any hack to make the server_api variable to be part of the request URL like <base_url>/$skip/4/$orderby/Releasedate

Feature Request: better pagination numbering

Currently the paginator will start at page 1 and create paging numbers for every single page. So if you have a million records and you are showing 10 per page, then you will have tons of numbers to page through displayed. It would be better to keep that at say 10 at a time.

Reference jQuery via jQuery (not $)

There's a list of 3 values — (function(...){ ... })(Backbone, _, $) at the end of global wrapper function. I'm getting some errors in my app due to $ referencing something other than jQuery (jQuery is in no-conflict mode). So this got me thinking... shouldn't we replace $ with jQuery for cases like this (when jQuery is in no-conflict mode)?

How to get data to the collection.info?

I'm using the requestPager and in the netflix-request-paging example in the render method you have:

var html = this.template(this.collection.info());

Which passes some useful information to the template for creating the pager UI. I would like to inject another variable into the info structure but I can't figure out how without modifying the info method in the backbone.paginator class itself. Is there a way to do this, or is there an alternative way to get the data? I am currently capturing the information in my parse method:

@totalDisplayRecords = response.iTotalDisplayRecords

But I don't know how to access totalDisplayRecords in my template. Any ideas would be much appreciated.

Creating models when using the clientPager

Hi Addy

I am using your paginator to pagination an employee list in my application, when I add a new employee to the collection the model is added to the collections "models" but not added to the "origmodels" object thus the new employee is overwritten when you go to the next page I have to re fetch my data, is there a patch for that?

Calculating counts of models on total collection

I cannot find a way to calculate the total count of models based on a filter without actually filtering the data. My work-around has been to create a second collection which is then filtered but, does not affect the view since it is not displayed.

Bootstrapping (or using reset) to initialise models in clientPager does not work

Hi,

I'm trying to bootstrap models when initialising the collection but that doesn't work. The collection shows no records after applying a sort, filtering or pagination.

That's because paging calculations based on the paginator_ui vars are done inside the "sync" method. I will create a pull request so that this calculation is done inside the initialize method.

Cheers,
Alan

Don't force js callback

Currently the library will force a callback of some type, but there could be the case of using an API on the same domain that will return pure JSON instead of "callback(...data...)".
Or maybe I dismissed some option to set that?

Regards!

PS: great lib, keep the good job!

EDIT 1:

Thinking about that issue a little bit further I realize that query params are totally useless when using a clientPager that loads all the data. You don't need none of the params as you have all the data, and you can decide what/how to show on the client side.

[Request] Multiple Instances on Same Page

I am trying to use Backbone.Paginator.js to run more than one app (multiple instances) on the same page.

I created a test (http://dl.dropbox.com/u/19974044/backbone.paginator.zip and navigate to backbone.paginator/examples/netflix-infinite-paging). I left the code as is for app.js and create app2.js, which is a clone of app.js but all the javascript code is located in one file and the app has been renamed to app2.

In Chrome/Firefox, two instances work on first load of the page but subsequent request/refreshes only load app2.js's data.

The example also functions differently on different browsers. It seems like the problem might be to caching issue/differences. For example, in Safari, it works sometimes (randomly) when refreshing the page.

In the example, the two apps/instances use the same JSON feed for demonstration/testing purpose, but it would be nice to use different feed sources for the multiple instances on the same page.

Wrong page on showPerPage change

After receiving, let's say, 12 results from the server we paginate them into 4 pages, each page with 3 results.
Going to page 3 and then selecting "Show 9 results per page" will clear everything and will show "19 - 12 of 12 results".

Regards!

Parse on collection not getting called

I'm trying to use backbone.paginator - and have, what I think is a proper setup between my Backbone.Paginatory.requestPager inheritied client collection. I can make calls to the server, and seem them coming by the log, and I can see the server parsing the parameters.

My problem is, parse isn't getting called on my collection after a fetch. I'm not sure what I'm missing to get this to work properly.

Any ideas?

obsolete dependencies

"dependencies": {
"backbone" : "~0.5.3",
"underscore": "1.3.1"
},

  1. backbone 0.5.3 would not work because missing method "on" in collection,
    which is used in \examples\netflix-client-paging\views\AppView.js
    backbone 0.9.2 is ok

  2. backbone.paginator.js version 0.1.54 needs _.result introduced in underscore 1.3.3 in line 88

requestPager break if fetch() is not the first function called

Hi,

Most of the functions used internally by requestPager refer to the paginator_ui value but on the collection itself (e.g. this.currentPage, example).

If we follow the settings described in the doc, one would only set paginator_ui hash then call functions. Although, most of the function will break as at this point the collection haven't been extended with paginator_ui. This only happen in the async function.

Doing so, requestPager will only work if .fetch() is the first method called on it (as this will run async, and as it's the only function not blocking on configuration error).

Right now, if one don't want to use fetch() to init the collection, he must setup manually the paginator_ui directly on the collection, or extend it as in the async function while initialize() is runned.

I'm not sure what could be the better fix for it, but I think it feels clumpsy that paginator_ui is duplicated on the collection itself. I'd probably go for one or the other and remove duplication (only paginator_ui or only attributes set directly on the collection).

Let me know what you think

paginator_core using collection 'url' as default if one not provided

I am still very new to Backbone and Javascript development and this is not a good idea please suggest what are the other options.

Can we make "queryOptions" inside "backbone.paginator.js" to use "self.url" if one not provided in "paginator_core"?


   var queryOptions = _.clone(self.paginator_core);
        
   // Create default values if no others are specified
  queryOptions = _.defaults(queryOptions, {
    timeout: 25000,
    cache: false,
    type: 'GET',
    dataType: 'jsonp',
    url: self.url
  });

Clearing filter rules

Looking at the Paginator.clientPager source, I can't find a convenience method suitable for clearing previously set filter rules. setFieldFilter is a no-op if it is passed an empty array or false. For now, I circumvented the issue by adding a clearFieldFilter method to my customized subclass:

My.Paginator = Backbone.Paginator.clientPager.extend({

    clearFieldFilter: function() {
        this.lastFieldFilterRiles = [];
        this.fieldFilterRules = [];
        this.pager();
        this.info();
    }

});

Shouldn't this functionality be included in the plugin? If there's already a way to clear filter rules please let me know.

Multiple sorting

It would be nice to have a way to sort a collection by multiple criteria. In my example I have a sorting criterion which permits the same values for multiple entries and thus I would like to further sort all entries with the same values with an unique criterion so that the final results have always the same sorting order.

Sort doesn't work out of the box with dates

Hi,

setSort method for clientPager doesn't work for date object right now, as it invokes .toString() method for converting the object for comparison, as implemented in the code:

_sort: function ( models, sort, direction ) {
            models = models.sort(function (a, b) {
                var ac = a.get(sort),
                    bc = b.get(sort);

                if ( !ac || !bc ) {
                    return 0;
                } else {
                    /* Make sure that both ac and bc are lowercase strings.
                    * .toString() first so we don't have to worry if ac or bc
                    * have other String-only methods.
                    */
                    ac = ac.toString().toLowerCase();
                    bc = bc.toString().toLowerCase();
                }

I know I can implement toString() method for dates, but I think it is dangerous to override an existing method of a native object and force us to use string for comparison.

It could be better to have it support all native js objects out of the box and in case the data being compared is a "object" also standardize a method such as .compareValue() so that developers could easily extend their custom objects and support sorting. If you think it is relevant, I will create a pull request for that.

Cheers,
Alan

Jasmine tests

Jasmine tests should be added in order to check the state of the library.
(I'm creating this just to let others know that I'm working on it)

Infinite Pagination Example not using 'add':true

Hello :-)

I would like to propose that the example for Infinite Pagination should use {'add':true} as options when calling requestNextPage.
Thereby the collection would contain all currently displayed items and not only the ones from the last request. Is that plausible?

Tobias

Bookmarking

I was just playing around with our clientPager example again and thought that it might be useful for us to also demonstrate there how bookmarking might work with the paginator. e.g you've navigated to page 5 of a particular set of results from a fixed feed, you want to be able to share it.

We could show how to have routing working with the paginator etc.

Thoughts @alexandernst?

Client pager startRecord calculation bug?

var start in Paginator.clientPager.pager() and

info.startRecord in Paginator.clientPager.info()

do not seem to be calculated correctly when you select a page number near the end of the list and then select a higher show-X records that would run off the end of the list.

To recreate in the clientPager() example, select page 9 then select show 12 per page.

Love the rest of paginator as it was the missing piece to the Backbone app I'm currently working on.

[Request] Local storage

Backbone.Paginator should be able to use the localStorage plugin for Backbone, but it can't.
The problem is that Backbone.Paginator overwrites the sync method, thus localStorage isn't getting any events/notifications/data at all.
Can't say how could we fix that, but this one is a must-have.
@addyosmani Any ideas?

Ajax executing error callback even though response was successful

I was trying to use the infinite paging example, but only the error callback was being executed after calling collection.pager(), even though all the responses were fine.

I dig down to see what was causing this and found that in the example it configures dataType as jsonp:
https://github.com/addyosmani/backbone.paginator/blob/master/examples/netflix-infinite-paging/collections/PaginatedCollection.js#L28

It may be a good idea to write a note above that line explaining the other dataTypes that can be used (http://api.jquery.com/jQuery.ajax/). Let me know if you agree or if you want me to send a pull request with some notes.

I changed mine to dataType: "json" and everything worked perfectly...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.