2

I use https://github.com/backbone-paginator/backbone.paginator to display data at a table whose columns are sortable. But when clicking on any header of a column, the sorting is done at the client instead of doing a new server request that should contain the attribute (e.g. name) that should be used to sort the results.

Base class

module.exports = Backbone.PageableCollection.extend({
    initialize: function (items, options) {
        options || (options = {});
        this.url = options.url || "/";
    },
    state: {
        pageSize: 15,
        firstPage: 0,
        currentPage: 0
    },
    queryParams: {
        sortKey: 'sort',
        pageSize: 'size',
        currentPage: 'page'
    },

parseState: function (resp) {
    return {totalRecords: resp && resp.length > 0 ? resp[0]['total_entries'] : 0};
},
parseRecords: function (resp) {
    return resp && resp.length > 0 ? resp[1] : [];
},

model: Backbone.NestedModel

});

Example Instantiation

collections.myTasks = new collections.PagingCollection([], {
    model: models.SyncModel.extend({
          url: URLs.TASKS
    }),
    url: URLs.MY_TASKS,
    state: {
         pageSize: 30,
         firstPage: 0,
         currentPage: 0,
    }
});

Columns

columns: [
    {
        name: "dueDate",
        label: "Due Date",
        cell: "date",
        filterCell: FilterCell,
        editable: false,
        width: "80px"
    },
    {
        name: "reminder",
        label: "Reminder",
        filterCell: FilterCell,
        cell: Backgrid.StringCell.extend({
            formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
                fromRaw: function (rawValue, model) {
                    return DateHelper.format(
                        IntervalHelper.calculateBefore(model.attributes['dueDate'], rawValue)
                    );
                }
            })
        }),
        editable: false,
        width: "80px"
    },
    {
        name: "name",
        label: "Subject",
        cell: "string",
        filterCell: FilterCell,
        editable: false,
        width: "auto"
    },
    {
        name: "taskStatusCtlg.taskStatus",
        label: "State",
        filterCell: SelectFilterCell.extend({
            filterField: 'taskStatus',
            addAllOption: true
        }),
        cell: "string",
        width: "75px"
    },
    {
        name: "assignedTo.alfrescoUserName",
        label: "Assigned To",
        cell: "string",
        filterCell: SelectFilterCell.extend({
            filterField: 'assignee',
            addAllOption: true
        }),
        editable: false,
        width: "120px"
    },
    {
        name: "taskTypeCtlg.taskType",
        label: "Type",
        cell: "string",
        filterCell: SelectFilterCell.extend({
            filterField: 'taskType',
            addAllOption: true
        }),
        editable: false,
        width: "70px"
    },
    {
        name: "mainDocument.name",
        label: "Case / Document",
        link: "mainDocument.id",
        cell: LinkCell,
        filterCell: FilterCell,
        editable: false,
        width: '160px'
    }
],

Fetching the data etc. is done without problems. But when clicking on a caret sorting is done on the client. But I need that attributes "sort" and "order" get append to the request URL when clicking on a column header (sorting on the server).

Current request:

http://localhost/tasks/user?page=0&size=30 

Needed request:

http://localhost/tasks/user?page=0&size=30&sort=name&order=asc 
Sébastien
  • 11,860
  • 11
  • 58
  • 78
enigma969
  • 397
  • 6
  • 21

1 Answers1

0

Paginator offers 3 modes for the fetching and sorting:

  • client: all on the client. Feed the data yourself.
  • server: Fetch the data from an API (e.g.: collection.getFirstPage()) and receive the total number of pages.
  • infinite: like the server mode, but best used with unknown number of pages. Like a search result from an external API.

Ensure that you're using the server value for the mode property on the PageableCollection.

var books = new Books([
  { name: "A Tale of Two Cities" },
  { name: "Lord of the Rings" },
  // ...
], {
  // Paginate and sort on the server side, this is the default.
  mode: "server",
});

or within your collection class definition:

module.exports = Backbone.PageableCollection.extend({
    mode: "server", // this is the default
    initialize: /*...*/

Other than that, this is likely solvable within Backgrid.

The default of Backgrid is to sort on the client. For a custom behavior, you can

Using a Backbone.PageableCollection

Set the collection property of the Grid.

var taskGrid = new Backgrid.Grid({
  collection: collections.myTasks,
  columns: [/*...*/],
});

Overriding the HeaderCell view

You are allow to use a different header cell class on columns. There is no restriction on what a header cell must do. In fact, any Backbone.View class can be used. However, if you wish to modify how the sorter behaves, you must implement the sorting protocol. See the JSDoc for details.

var SelectAllHeaderCell = Backgrid.HeaderCell.extend({
  // Implement your "select all" logic here
});

var grid = new Backgrid.Grid({

  columns: [{
    name: "selected",
    label: "",
    sortable: false,
    cell: "boolean",
    headerCell: SelectAllHeaderCell
  }],

  collection: col
});

Note (2017/01/30): Links to the API documentation within the documentation are not up to date, this is being discussed in issue #664.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • Is it really necessary to implement an own logic? I saw some examples where the switch from client/server is achieved in the background without any custom implementation. But using this code doesn't work for me. – enigma969 Jan 30 '17 at 20:43
  • @enigma969 I added information on Paginator modes, but the default should be correct. You'll probably need to catch the click for the sorting, adjust the collection sort field, then fetch the page. – Emile Bergeron Jan 30 '17 at 21:00
  • @enigma969 I added information on adding a `PageableCollection` collection to the grid – Emile Bergeron Jan 31 '17 at 04:11