mirror of
https://github.com/Mottie/tablesorter.git
synced 2024-11-15 23:54:22 +00:00
AJAX paging updates. This patch fixes issues with update events being re-triggered continuously and AJAX error handling being bound too many times. It also adds support for passing filtering parameters with the AJAX request.
This commit is contained in:
parent
351e3ad699
commit
3d415333cc
@ -11,10 +11,12 @@
|
|||||||
// target the pager markup
|
// target the pager markup
|
||||||
container: null,
|
container: null,
|
||||||
|
|
||||||
// use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}"
|
// use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}"
|
||||||
// where {page} is replaced by the page number and {size} is replaced by the number of records to show
|
// where {page} is replaced by the page number, {size} is replaced by the number of records to show,
|
||||||
// {sortList:col} adds the sortList to the url into a "col" array.
|
// {sortList:col} adds the sortList to the url into a "col" array, and {filterList:fcol} adds
|
||||||
|
// the filterList to the url into an "fcol" array.
|
||||||
// So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url
|
// So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url
|
||||||
|
// and a filterList = [[2,Blue],[3,13]] becomes "&fcol[2]=Blue&fcol[3]=13" in the url
|
||||||
ajaxUrl: null,
|
ajaxUrl: null,
|
||||||
|
|
||||||
// process ajax so that the following information is returned:
|
// process ajax so that the following information is returned:
|
||||||
@ -69,7 +71,8 @@
|
|||||||
totalRows: 0,
|
totalRows: 0,
|
||||||
totalPages: 0,
|
totalPages: 0,
|
||||||
filteredRows: 0,
|
filteredRows: 0,
|
||||||
filteredPages: 0
|
filteredPages: 0,
|
||||||
|
cssErrorRow: 'tablesorter-errorRow'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,7 +84,6 @@
|
|||||||
r = 'removeClass',
|
r = 'removeClass',
|
||||||
d = c.cssDisabled,
|
d = c.cssDisabled,
|
||||||
dis = !!disable,
|
dis = !!disable,
|
||||||
// tr = Math.min( c.totalRows, c.filteredRows ),
|
|
||||||
tp = Math.min( c.totalPages, c.filteredPages );
|
tp = Math.min( c.totalPages, c.filteredPages );
|
||||||
if ( c.updateArrows ) {
|
if ( c.updateArrows ) {
|
||||||
$(c.cssFirst + ',' + c.cssPrev, c.container)[ ( dis || c.page === 0 ) ? a : r ](d);
|
$(c.cssFirst + ',' + c.cssPrev, c.container)[ ( dis || c.page === 0 ) ? a : r ](d);
|
||||||
@ -90,7 +92,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
updatePageDisplay = function(table, c) {
|
updatePageDisplay = function(table, c) {
|
||||||
var i, p, s, t, out, f = $(table).hasClass('hasFilters');
|
var i, p, s, t, out, f = $(table).hasClass('hasFilters') && !c.ajaxUrl;
|
||||||
c.filteredRows = (f) ? $(table).find('tbody tr:not(.filtered)').length : c.totalRows;
|
c.filteredRows = (f) ? $(table).find('tbody tr:not(.filtered)').length : c.totalRows;
|
||||||
c.filteredPages = (f) ? Math.ceil( c.filteredRows / c.size ) : c.totalPages;
|
c.filteredPages = (f) ? Math.ceil( c.filteredRows / c.size ) : c.totalPages;
|
||||||
if ( Math.min( c.totalPages, c.filteredPages ) > 0 ) {
|
if ( Math.min( c.totalPages, c.filteredPages ) > 0 ) {
|
||||||
@ -187,7 +189,7 @@
|
|||||||
tc = table.config,
|
tc = table.config,
|
||||||
$b = $(table.tBodies).filter(':not(.' + tc.cssInfoBlock + ')'),
|
$b = $(table.tBodies).filter(':not(.' + tc.cssInfoBlock + ')'),
|
||||||
hl = $t.find('thead th').length, tds = '',
|
hl = $t.find('thead th').length, tds = '',
|
||||||
err = '<tr class="' + tc.selectorRemove + '"><td style="text-align: center;" colspan="' + hl + '">' +
|
err = '<tr class="' + c.cssErrorRow + '"><td style="text-align: center;" colspan="' + hl + '">' +
|
||||||
(exception ? exception.message + ' (' + exception.name + ')' : 'No rows found') + '</td></tr>',
|
(exception ? exception.message + ' (' + exception.name + ')' : 'No rows found') + '</td></tr>',
|
||||||
result = c.ajaxProcessing(data) || [ 0, [] ],
|
result = c.ajaxProcessing(data) || [ 0, [] ],
|
||||||
d = result[1] || [],
|
d = result[1] || [],
|
||||||
@ -225,13 +227,17 @@
|
|||||||
$f.eq(j).html( th[j] );
|
$f.eq(j).html( th[j] );
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$t.find('thead tr.' + c.cssErrorRow).remove(); //Clean up any previous error.
|
||||||
if ( exception ) {
|
if ( exception ) {
|
||||||
// add error row to thead instead of tbody, or clicking on the header will result in a parser error
|
// add error row to thead instead of tbody, or clicking on the header will result in a parser error
|
||||||
$t.find('thead').append(err);
|
$t.find('thead').append(err);
|
||||||
} else {
|
} else {
|
||||||
$b.html( tds ); // add tbody
|
$b.html( tds ); // add tbody
|
||||||
}
|
}
|
||||||
|
if (tc.showProcessing) {
|
||||||
$.tablesorter.isProcessing(table); // remove loading icon
|
$.tablesorter.isProcessing(table); // remove loading icon
|
||||||
|
}
|
||||||
$t.trigger('update');
|
$t.trigger('update');
|
||||||
c.totalRows = result[0] || 0;
|
c.totalRows = result[0] || 0;
|
||||||
c.totalPages = Math.ceil( c.totalRows / c.size );
|
c.totalPages = Math.ceil( c.totalRows / c.size );
|
||||||
@ -246,30 +252,54 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
getAjax = function(table, c){
|
getAjax = function(table, c){
|
||||||
var url = (c.ajaxUrl) ? c.ajaxUrl.replace(/\{page\}/g, c.page).replace(/\{size\}/g, c.size) : '',
|
var url = getAjaxUrl(table, c),
|
||||||
arry = [],
|
tc = table.config;
|
||||||
sl = table.config.sortList,
|
|
||||||
col = url.match(/\{sortList[\s+]?:[\s+]?(.*)\}/);
|
|
||||||
if (col) {
|
|
||||||
col = col[1];
|
|
||||||
$.each(sl, function(i,v){
|
|
||||||
arry.push(col + '[' + v[0] + ']=' + v[1]);
|
|
||||||
});
|
|
||||||
// if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col"
|
|
||||||
url = url.replace(/\{sortList[\s+]?:[\s+]?(.*)\}/g, arry.length ? arry.join('&') : col );
|
|
||||||
}
|
|
||||||
if ( url !== '' ) {
|
if ( url !== '' ) {
|
||||||
// loading icon
|
if (tc.showProcessing) {
|
||||||
$.tablesorter.isProcessing(table, true);
|
$.tablesorter.isProcessing(table, true); // show loading icon
|
||||||
$(document).ajaxError(function(e, xhr, settings, exception) {
|
}
|
||||||
|
$(document).bind('ajaxError.pager', function(e, xhr, settings, exception) {
|
||||||
|
if (settings.url == url) {
|
||||||
renderAjax(null, table, c, exception);
|
renderAjax(null, table, c, exception);
|
||||||
|
$(document).unbind('ajaxError.pager');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
$.getJSON(url, function(data) {
|
$.getJSON(url, function(data) {
|
||||||
renderAjax(data, table, c);
|
renderAjax(data, table, c);
|
||||||
|
$(document).unbind('ajaxError.pager');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getAjaxUrl = function(table, c) {
|
||||||
|
var url = (c.ajaxUrl) ? c.ajaxUrl.replace(/\{page\}/g, c.page).replace(/\{size\}/g, c.size) : '',
|
||||||
|
sl = table.config.sortList,
|
||||||
|
fl = c.currentFilters || [],
|
||||||
|
sortCol = url.match(/\{sortList[\s+]?:[\s+]?([^}]*)\}/),
|
||||||
|
filterCol = url.match(/\{filterList[\s+]?:[\s+]?([^}]*)\}/),
|
||||||
|
arry = [];
|
||||||
|
if (sortCol) {
|
||||||
|
sortCol = sortCol[1];
|
||||||
|
$.each(sl, function(i,v){
|
||||||
|
arry.push(sortCol + '[' + v[0] + ']=' + v[1]);
|
||||||
|
});
|
||||||
|
// if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col"
|
||||||
|
url = url.replace(/\{sortList[\s+]?:[\s+]?([^}]*)\}/g, arry.length ? arry.join('&') : sortCol );
|
||||||
|
}
|
||||||
|
if (filterCol) {
|
||||||
|
filterCol = filterCol[1];
|
||||||
|
$.each(fl, function(i,v){
|
||||||
|
if (v) {
|
||||||
|
arry.push(filterCol + '[' + i + ']=' + encodeURIComponent(v));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// if the arry is empty, just add the fcol parameter... "&{filterList:fcol}" becomes "&fcol"
|
||||||
|
url = url.replace(/\{filterList[\s+]?:[\s+]?([^}]*)\}/g, arry.length ? arry.join('&') : filterCol );
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
|
||||||
renderTable = function(table, rows, c) {
|
renderTable = function(table, rows, c) {
|
||||||
var i, j, o,
|
var i, j, o,
|
||||||
f = document.createDocumentFragment(),
|
f = document.createDocumentFragment(),
|
||||||
@ -329,13 +359,13 @@
|
|||||||
if ( c.page < 0 || c.page > ( p - 1 ) ) {
|
if ( c.page < 0 || c.page > ( p - 1 ) ) {
|
||||||
c.page = 0;
|
c.page = 0;
|
||||||
}
|
}
|
||||||
// change if page changed - fixes #182
|
if (c.ajax) {
|
||||||
if (c.ajax && $.data(table, 'pagerLastPage') !== c.page) {
|
|
||||||
getAjax(table, c);
|
getAjax(table, c);
|
||||||
} else if (!c.ajax) {
|
} else if (!c.ajax) {
|
||||||
renderTable(table, table.config.rowsCopy, c);
|
renderTable(table, table.config.rowsCopy, c);
|
||||||
}
|
}
|
||||||
$.data(table, 'pagerLastPage', c.page);
|
$.data(table, 'pagerLastPage', c.page);
|
||||||
|
$.data(table, 'pagerUpdateTriggered', true);
|
||||||
if (c.initialized) { $(table).trigger('pageMoved', c); }
|
if (c.initialized) { $(table).trigger('pageMoved', c); }
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -414,6 +444,7 @@
|
|||||||
var config = this.config,
|
var config = this.config,
|
||||||
c = config.pager = $.extend( {}, $.tablesorterPager.defaults, settings ),
|
c = config.pager = $.extend( {}, $.tablesorterPager.defaults, settings ),
|
||||||
table = this,
|
table = this,
|
||||||
|
tc = table.config,
|
||||||
$t = $(table),
|
$t = $(table),
|
||||||
pager = $(c.container).addClass('tablesorter-pager').show(); // added in case the pager is reinitialized after being destroyed.
|
pager = $(c.container).addClass('tablesorter-pager').show(); // added in case the pager is reinitialized after being destroyed.
|
||||||
config.appender = $this.appender;
|
config.appender = $this.appender;
|
||||||
@ -423,6 +454,9 @@
|
|||||||
if ( typeof(c.ajaxUrl) === 'string' ) {
|
if ( typeof(c.ajaxUrl) === 'string' ) {
|
||||||
// ajax pager; interact with database
|
// ajax pager; interact with database
|
||||||
c.ajax = true;
|
c.ajax = true;
|
||||||
|
//When filtering with ajax, allow only custom filtering function, disable default filtering since it will be done server side.
|
||||||
|
tc.widgetOptions.filter_serversideFiltering = true;
|
||||||
|
tc.serverSideSorting = true;
|
||||||
getAjax(table, c);
|
getAjax(table, c);
|
||||||
} else {
|
} else {
|
||||||
c.ajax = false;
|
c.ajax = false;
|
||||||
@ -431,16 +465,26 @@
|
|||||||
hideRowsSetup(table, c);
|
hideRowsSetup(table, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$(table)
|
||||||
|
.unbind('filterStart.pager')
|
||||||
|
.bind('filterStart.pager', function(e, filters) {
|
||||||
|
c.currentFilters = filters;
|
||||||
|
});
|
||||||
|
|
||||||
// update pager after filter widget completes
|
// update pager after filter widget completes
|
||||||
$(table)
|
$(table)
|
||||||
.unbind('filterEnd.pager updateComplete.pager ')
|
.unbind('filterEnd.pager sortEnd.pager')
|
||||||
.bind('filterEnd.pager updateComplete.pager', function() {
|
.bind('filterEnd.pager sortEnd.pager', function() {
|
||||||
if ($(this).hasClass('hasFilters')) {
|
//Prevent infinite event loops from occuring by setting this in all moveToPage calls and catching it here.
|
||||||
|
if ($.data(table, 'pagerUpdateTriggered')) {
|
||||||
|
$.data(table, 'pagerUpdateTriggered', false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
c.page = 0;
|
c.page = 0;
|
||||||
updatePageDisplay(table, c);
|
updatePageDisplay(table, c);
|
||||||
moveToPage(table, c);
|
moveToPage(table, c);
|
||||||
changeHeight(table, c);
|
changeHeight(table, c);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if ( $(c.cssGoto, pager).length ) {
|
if ( $(c.cssGoto, pager).length ) {
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
sortMultiSortKey : 'shiftKey', // key used to select additional columns
|
sortMultiSortKey : 'shiftKey', // key used to select additional columns
|
||||||
usNumberFormat : true, // false for German "1.234.567,89" or French "1 234 567,89"
|
usNumberFormat : true, // false for German "1.234.567,89" or French "1 234 567,89"
|
||||||
delayInit : false, // if false, the parsed table contents will not update until the first sort
|
delayInit : false, // if false, the parsed table contents will not update until the first sort
|
||||||
|
serverSideSorting : false, // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.
|
||||||
|
|
||||||
// sort options
|
// sort options
|
||||||
headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
|
headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
|
||||||
@ -459,6 +460,9 @@
|
|||||||
var dynamicExp, sortWrapper, col, mx = 0, dir = 0, tc = table.config,
|
var dynamicExp, sortWrapper, col, mx = 0, dir = 0, tc = table.config,
|
||||||
sortList = tc.sortList, l = sortList.length, bl = table.tBodies.length,
|
sortList = tc.sortList, l = sortList.length, bl = table.tBodies.length,
|
||||||
sortTime, i, j, k, c, colMax, cache, lc, s, e, order, orgOrderCol;
|
sortTime, i, j, k, c, colMax, cache, lc, s, e, order, orgOrderCol;
|
||||||
|
if (tc.serverSideSorting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (tc.debug) { sortTime = new Date(); }
|
if (tc.debug) { sortTime = new Date(); }
|
||||||
for (k = 0; k < bl; k++) {
|
for (k = 0; k < bl; k++) {
|
||||||
colMax = tc.cache[k].colMax;
|
colMax = tc.cache[k].colMax;
|
||||||
|
@ -282,6 +282,7 @@ $.tablesorter.addWidget({
|
|||||||
filter_searchDelay : 300 // typing delay in milliseconds before starting a search
|
filter_searchDelay : 300 // typing delay in milliseconds before starting a search
|
||||||
filter_startsWith : false // if true, filter start from the beginning of the cell contents
|
filter_startsWith : false // if true, filter start from the beginning of the cell contents
|
||||||
filter_useParsedData : false // filter all data using parsed content
|
filter_useParsedData : false // filter all data using parsed content
|
||||||
|
filter_serversideFiltering : false // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used.
|
||||||
**************************/
|
**************************/
|
||||||
$.tablesorter.addWidget({
|
$.tablesorter.addWidget({
|
||||||
id: "filter",
|
id: "filter",
|
||||||
@ -353,7 +354,7 @@ $.tablesorter.addWidget({
|
|||||||
$tb = $.tablesorter.processTbody(table, $(b[k]), true);
|
$tb = $.tablesorter.processTbody(table, $(b[k]), true);
|
||||||
$tr = $tb.children('tr');
|
$tr = $tb.children('tr');
|
||||||
l = $tr.length;
|
l = $tr.length;
|
||||||
if (cv === ''){
|
if (cv === '' || wo.filter_serversideFiltering){
|
||||||
$tr.show().removeClass('filtered');
|
$tr.show().removeClass('filtered');
|
||||||
} else {
|
} else {
|
||||||
// loop through the rows
|
// loop through the rows
|
||||||
|
Loading…
Reference in New Issue
Block a user