Tablesorter 总是在内容编辑后重新加载第一页
Tablesorter always reloads first page after content-edit
我有一个带有表格排序器实现的应用程序。它具有内容可编辑、过滤和 ajax 服务器寻呼机的特点。一切正常,除了一个问题:每次用户在页面 > 1 上提交编辑后的值时,都会提交内容,但 tablesorter 会重新加载第一页。
查看 xhr 请求很明显发出了新的 get 请求(我猜是在幕后,在我的代码中我没有触发任何更新或重新加载)。反正对我来说很好,刷新内容没问题,但我想保留用户编辑前的页面。
如我所见,问题仅发生在页面参数上:如果我更改每页元素的数量,在列中放置过滤器,或者对一个或多个字段进行排序,tablesorter 会跟踪它们,并且它们是在请求 url 参数中正确更新,页面参数除外,该参数始终恢复为 0。
从 xhr 请求端查看的进度示例:
第一个请求(默认): vlansummarys?page=0&size=10&col[10]=0&col[8]=0&col[7]=0&fcol
已添加过滤器: vlansummarys?page=0&size=10&col[10]=0&col[8]=0&col[7]=0&fcol[3]=monocos
页面元素10到20: vlansummarys?page=0&size=20&col[10]=0&col[8]=0&col[7]=0&fcol[ 3]=单体
添加了新的排序字段: vlansummarys?page=0&size=20&col[10]=0&col[8]=0&col[7]=0&col[3] =0&fcol[3]=单体
页面更改为 2: vlansummarys?page=1&size=20&col[10]=0&col[8]=0&col[7]=0&col[3] =0&fcol[3]=单体
内容编辑,之后调用: vlansummarys?page=0&size=20&col[10]=0&col[8]=0&col[7]=0&col [3]=0&fcol[3]=单体
编辑
根据要求,我发布了我的代码。由于很难将其简化为一个简单的工作示例,因此我将粘贴我所有的 tablesorter 初始化函数。它不能单独工作,因为它依赖于页面上计算的其他数据和变量,但我想它应该给出一个很好的主意。请向我询问任何可能有帮助的详细信息。
function LoadTable() {
$('#table').tablesorter({
theme: 'bootstrap',
//widthFixed: true,
zebra: [
"even",
"odd"],
dateFormat: "ddmmyyyy",
headerTemplate: '{content}',
sortList: [[10, 0], [8, 0], [7, 0]], //Order by AdR del Kit ASC, AdR ASC, Centrale ASC
initWidgets: true,
widgets: bReadOnly ? ['zebra', 'columns', 'filter', 'uitheme'] : ['zebra', 'columns', 'filter', 'uitheme', 'editable'],
widgetOptions: {
filter_columnFilters: true,
filter_cssFilter: arrHeaderFields,
editable_columns: (bReadOnly ? null : [21]), // or "0-2" (v2.14.2); point to the columns to make editable (zero-based index)
editable_enterToAccept: true, // press enter to accept content, or click outside if false
editable_autoAccept: false, // accepts any changes made to the table cell automatically (v2.17.6)
editable_autoResort: false, // auto resort after the content has changed.
editable_noEdit: 'no-edit', // class name of cell that is not editable
editable_editComplete: 'editComplete', // event fired after the table content has been edited
editable_validate: null, // return a valid string: function(text, original){ return text; }
editable_focused: null,/*function (txt, columnIndex, $element) {
// $element is the div, not the td
// to get the td, use $element.closest('td')
//$element.addClass('focused');
$element.removeClass("emptyPlaceholder");
//SelectActivationDateText($element.closest('td'));
},*/
editable_blur: null,/*function (txt, columnIndex, $element) {
// $element is the div, not the td
// to get the td, use $element.closest('td')
//$element.removeClass('focused');
RestoreCellStyle($element);
},*/
editable_selectAll: null,/*true,function (txt, columnIndex, $element) {
// note $element is the div inside of the table cell, so use $element.closest('td') to get the cell
// only select everthing within the element when the content starts with the letter "B"
//return /^b/i.test(txt) && columnIndex === 0;
},*/
editable_wrapContent: null,//'<div>', // wrap all editable cell content... makes this widget work in IE, and with autocomplete
/*reorder_axis: 'x', // 'x' or 'xy'
reorder_delay: 300,
reorder_helperClass: 'tablesorter-reorder-helper',
reorder_helperBar: 'tablesorter-reorder-helper-bar',
reorder_noReorder: 'reorder-false',
reorder_blocked: 'reorder-block-left reorder-block-end',
reorder_complete: null // callback*/
},
}).tablesorterPager({
// target the pager markup - see the HTML block below
container: $(".pager"),
// use this url format "http:/mydatabase.com?page={page}&size={size}"
ajaxUrl: "/application/vlansummarys?page={page}&size={size}&{sortList:col}&{filterList:fcol}",
// modify the url after all processing has been applied
customAjaxUrl: function(table, url) { return url; },
ajaxProcessing: function (data) {
if (data && data.hasOwnProperty('rows')) {
var str = "", d = data.rows,
// total number of rows (required)
total = data.total_rows,
// len should match pager set size (c.size)
len = d.length;
for (var i = 0; i < len; i++) {
str += '<tr>';
for (var column = 0; column < orderedFieldMapping.length; column++) {
//Distinzione temporanea per gestire i casi di dato non presente (Data Attivazione) e handler di selezione
if (orderedFieldMapping[column].toUpperCase() != 'ACTIVATIONDATE' || bReadOnly)
str += '<td class="' + orderedFieldMapping[column].toUpperCase() + '"' + ($('#' + orderedFieldMapping[column].toUpperCase()).prop('checked') ? '' : 'style="display:none;"') + '><div>' + (eval('d[i].' + orderedFieldMapping[column]) != null ? eval('d[i].' + orderedFieldMapping[column]) : '') + '</div></td>';
else
str += '<td title="Inserire la data nel formato gg/mm/aaaa (click per inserimento)" class="' + orderedFieldMapping[column].toUpperCase() + '"' + ($('#' + orderedFieldMapping[column].toUpperCase()).prop('checked') ? '' : 'style="display:none;"') + '><div contenteditable="true" ' + (eval('d[i].' + orderedFieldMapping[column]) != null ? '' : 'class="emptyPlaceholder" ') + 'onmouseup="javascript:SelectActivationDateText(this);" onblur="javascript:RestoreCellStyle(this);">' + (eval('d[i].' + orderedFieldMapping[column]) != null ? eval('d[i].' + orderedFieldMapping[column]) : emptyTextString) + '</div></td>';
}
str += '</tr>';
}
// in version 2.10, you can optionally return $(rows) a set of table rows within a jQuery object
return [total, $(str)];
}
},
ajaxObject: {
dataType: 'json'
},
// output string - default is '{page}/{totalPages}';
// possible variables:
// {page}, {totalPages}, {startRow}, {endRow} and {totalRows}
output: '{startRow} to {endRow} ({totalRows})',
// apply disabled classname to the pager arrows when the rows at
// either extreme is visible - default is true
updateArrows: true,
// starting page of the pager (zero based index)
page: 0,
// Number of visible rows - default is 10
size: 20,
//Reset pager to this page after filtering; set to desired page number (zero-based index), or false to not change page at filter start (Updated v2.16).
pageReset: false,
// if true, the table will remain the same height no matter how many
// records are displayed. The space is made up by an empty
// table row set to a height to compensate; default is false
fixedHeight: true,
// remove rows from the table to speed up the sort of large tables.
// setting this to false, only hides the non-visible rows; needed
// if you plan to add/remove rows with the pager enabled.
removeRows: false,
// css class names of pager arrows
// next page arrow
cssNext: '.next',
// previous page arrow
cssPrev: '.prev',
// go to first page arrow
cssFirst: '.first',
// go to last page arrow
cssLast: '.last',
// select dropdown to allow choosing a page
cssGoto: '.gotoPage',
// location of where the "output" is displayed
cssPageDisplay: '.pagedisplay',
// dropdown that sets the "size" option
cssPageSize: '.pagesize',
// class added to arrows when at the extremes
// (i.e. prev/first arrows are "disabled" when on the first page)
// Note there is no period "." in front of this class name
cssDisabled: 'disabled'
}).children('tbody').on('editComplete', 'td', function() {
var $this = $(this),
//$allRows = $this.closest('table')[0].config.$tbodies.children('tr'),
newContent = $this.text(),
/*cellIndex = this.cellIndex, // there shouldn't be any colspans in the tbody
rowIndex = $allRows.index($this.closest('tr')),*/
id = $this.closest('tr').find('td.ID').text();
$.ajax({
type: "POST",
crossDomain: true,
url: '/application/vlansummarys/update/' + id,
data: JSON.stringify({ activationDate: newContent }),
dataType: "text",
contentType: "application/json; charset=utf-8",
error: function(xhr, textStatus, errorThrown) {
alert("Errore durante l'inserimento: il dato inserito non è corretto. Contattare sistemi informativi se si ritiene che il messaggio d'errore sia sbagliato.");
},
success: function(data, textStatus, xhr) {
//console.log(xhr);
if ($this.find('div').hasClass('emptyPlaceholder'))
$this.find('div').removeClass('emptyPlaceholder');
},
});
});
}
所以问题原来是寻呼机的问题addon/widget。编辑单元格时,editable 小部件会触发 "updateCell" 事件以更新内部缓存。此过程完成后,核心插件会触发 "updateComplete" 事件。
在寻呼程序代码中,当触发 "updateComplete" 事件时,它会不恰当地更新总行数和总页数,因为正在使用 ajax 并且它只计算当前在 [=] 中的行数27=].
所以基本上,我添加了一个检查以防止在使用 ajax 时重新计算 page/row 计数。
从 GitHub 存储库 master 分支中获取此 latest update for the pager。
我有一个带有表格排序器实现的应用程序。它具有内容可编辑、过滤和 ajax 服务器寻呼机的特点。一切正常,除了一个问题:每次用户在页面 > 1 上提交编辑后的值时,都会提交内容,但 tablesorter 会重新加载第一页。
查看 xhr 请求很明显发出了新的 get 请求(我猜是在幕后,在我的代码中我没有触发任何更新或重新加载)。反正对我来说很好,刷新内容没问题,但我想保留用户编辑前的页面。
如我所见,问题仅发生在页面参数上:如果我更改每页元素的数量,在列中放置过滤器,或者对一个或多个字段进行排序,tablesorter 会跟踪它们,并且它们是在请求 url 参数中正确更新,页面参数除外,该参数始终恢复为 0。
从 xhr 请求端查看的进度示例:
第一个请求(默认): vlansummarys?page=0&size=10&col[10]=0&col[8]=0&col[7]=0&fcol
已添加过滤器: vlansummarys?page=0&size=10&col[10]=0&col[8]=0&col[7]=0&fcol[3]=monocos
页面元素10到20: vlansummarys?page=0&size=20&col[10]=0&col[8]=0&col[7]=0&fcol[ 3]=单体
添加了新的排序字段: vlansummarys?page=0&size=20&col[10]=0&col[8]=0&col[7]=0&col[3] =0&fcol[3]=单体
页面更改为 2: vlansummarys?page=1&size=20&col[10]=0&col[8]=0&col[7]=0&col[3] =0&fcol[3]=单体
内容编辑,之后调用: vlansummarys?page=0&size=20&col[10]=0&col[8]=0&col[7]=0&col [3]=0&fcol[3]=单体
编辑
根据要求,我发布了我的代码。由于很难将其简化为一个简单的工作示例,因此我将粘贴我所有的 tablesorter 初始化函数。它不能单独工作,因为它依赖于页面上计算的其他数据和变量,但我想它应该给出一个很好的主意。请向我询问任何可能有帮助的详细信息。
function LoadTable() {
$('#table').tablesorter({
theme: 'bootstrap',
//widthFixed: true,
zebra: [
"even",
"odd"],
dateFormat: "ddmmyyyy",
headerTemplate: '{content}',
sortList: [[10, 0], [8, 0], [7, 0]], //Order by AdR del Kit ASC, AdR ASC, Centrale ASC
initWidgets: true,
widgets: bReadOnly ? ['zebra', 'columns', 'filter', 'uitheme'] : ['zebra', 'columns', 'filter', 'uitheme', 'editable'],
widgetOptions: {
filter_columnFilters: true,
filter_cssFilter: arrHeaderFields,
editable_columns: (bReadOnly ? null : [21]), // or "0-2" (v2.14.2); point to the columns to make editable (zero-based index)
editable_enterToAccept: true, // press enter to accept content, or click outside if false
editable_autoAccept: false, // accepts any changes made to the table cell automatically (v2.17.6)
editable_autoResort: false, // auto resort after the content has changed.
editable_noEdit: 'no-edit', // class name of cell that is not editable
editable_editComplete: 'editComplete', // event fired after the table content has been edited
editable_validate: null, // return a valid string: function(text, original){ return text; }
editable_focused: null,/*function (txt, columnIndex, $element) {
// $element is the div, not the td
// to get the td, use $element.closest('td')
//$element.addClass('focused');
$element.removeClass("emptyPlaceholder");
//SelectActivationDateText($element.closest('td'));
},*/
editable_blur: null,/*function (txt, columnIndex, $element) {
// $element is the div, not the td
// to get the td, use $element.closest('td')
//$element.removeClass('focused');
RestoreCellStyle($element);
},*/
editable_selectAll: null,/*true,function (txt, columnIndex, $element) {
// note $element is the div inside of the table cell, so use $element.closest('td') to get the cell
// only select everthing within the element when the content starts with the letter "B"
//return /^b/i.test(txt) && columnIndex === 0;
},*/
editable_wrapContent: null,//'<div>', // wrap all editable cell content... makes this widget work in IE, and with autocomplete
/*reorder_axis: 'x', // 'x' or 'xy'
reorder_delay: 300,
reorder_helperClass: 'tablesorter-reorder-helper',
reorder_helperBar: 'tablesorter-reorder-helper-bar',
reorder_noReorder: 'reorder-false',
reorder_blocked: 'reorder-block-left reorder-block-end',
reorder_complete: null // callback*/
},
}).tablesorterPager({
// target the pager markup - see the HTML block below
container: $(".pager"),
// use this url format "http:/mydatabase.com?page={page}&size={size}"
ajaxUrl: "/application/vlansummarys?page={page}&size={size}&{sortList:col}&{filterList:fcol}",
// modify the url after all processing has been applied
customAjaxUrl: function(table, url) { return url; },
ajaxProcessing: function (data) {
if (data && data.hasOwnProperty('rows')) {
var str = "", d = data.rows,
// total number of rows (required)
total = data.total_rows,
// len should match pager set size (c.size)
len = d.length;
for (var i = 0; i < len; i++) {
str += '<tr>';
for (var column = 0; column < orderedFieldMapping.length; column++) {
//Distinzione temporanea per gestire i casi di dato non presente (Data Attivazione) e handler di selezione
if (orderedFieldMapping[column].toUpperCase() != 'ACTIVATIONDATE' || bReadOnly)
str += '<td class="' + orderedFieldMapping[column].toUpperCase() + '"' + ($('#' + orderedFieldMapping[column].toUpperCase()).prop('checked') ? '' : 'style="display:none;"') + '><div>' + (eval('d[i].' + orderedFieldMapping[column]) != null ? eval('d[i].' + orderedFieldMapping[column]) : '') + '</div></td>';
else
str += '<td title="Inserire la data nel formato gg/mm/aaaa (click per inserimento)" class="' + orderedFieldMapping[column].toUpperCase() + '"' + ($('#' + orderedFieldMapping[column].toUpperCase()).prop('checked') ? '' : 'style="display:none;"') + '><div contenteditable="true" ' + (eval('d[i].' + orderedFieldMapping[column]) != null ? '' : 'class="emptyPlaceholder" ') + 'onmouseup="javascript:SelectActivationDateText(this);" onblur="javascript:RestoreCellStyle(this);">' + (eval('d[i].' + orderedFieldMapping[column]) != null ? eval('d[i].' + orderedFieldMapping[column]) : emptyTextString) + '</div></td>';
}
str += '</tr>';
}
// in version 2.10, you can optionally return $(rows) a set of table rows within a jQuery object
return [total, $(str)];
}
},
ajaxObject: {
dataType: 'json'
},
// output string - default is '{page}/{totalPages}';
// possible variables:
// {page}, {totalPages}, {startRow}, {endRow} and {totalRows}
output: '{startRow} to {endRow} ({totalRows})',
// apply disabled classname to the pager arrows when the rows at
// either extreme is visible - default is true
updateArrows: true,
// starting page of the pager (zero based index)
page: 0,
// Number of visible rows - default is 10
size: 20,
//Reset pager to this page after filtering; set to desired page number (zero-based index), or false to not change page at filter start (Updated v2.16).
pageReset: false,
// if true, the table will remain the same height no matter how many
// records are displayed. The space is made up by an empty
// table row set to a height to compensate; default is false
fixedHeight: true,
// remove rows from the table to speed up the sort of large tables.
// setting this to false, only hides the non-visible rows; needed
// if you plan to add/remove rows with the pager enabled.
removeRows: false,
// css class names of pager arrows
// next page arrow
cssNext: '.next',
// previous page arrow
cssPrev: '.prev',
// go to first page arrow
cssFirst: '.first',
// go to last page arrow
cssLast: '.last',
// select dropdown to allow choosing a page
cssGoto: '.gotoPage',
// location of where the "output" is displayed
cssPageDisplay: '.pagedisplay',
// dropdown that sets the "size" option
cssPageSize: '.pagesize',
// class added to arrows when at the extremes
// (i.e. prev/first arrows are "disabled" when on the first page)
// Note there is no period "." in front of this class name
cssDisabled: 'disabled'
}).children('tbody').on('editComplete', 'td', function() {
var $this = $(this),
//$allRows = $this.closest('table')[0].config.$tbodies.children('tr'),
newContent = $this.text(),
/*cellIndex = this.cellIndex, // there shouldn't be any colspans in the tbody
rowIndex = $allRows.index($this.closest('tr')),*/
id = $this.closest('tr').find('td.ID').text();
$.ajax({
type: "POST",
crossDomain: true,
url: '/application/vlansummarys/update/' + id,
data: JSON.stringify({ activationDate: newContent }),
dataType: "text",
contentType: "application/json; charset=utf-8",
error: function(xhr, textStatus, errorThrown) {
alert("Errore durante l'inserimento: il dato inserito non è corretto. Contattare sistemi informativi se si ritiene che il messaggio d'errore sia sbagliato.");
},
success: function(data, textStatus, xhr) {
//console.log(xhr);
if ($this.find('div').hasClass('emptyPlaceholder'))
$this.find('div').removeClass('emptyPlaceholder');
},
});
});
}
所以问题原来是寻呼机的问题addon/widget。编辑单元格时,editable 小部件会触发 "updateCell" 事件以更新内部缓存。此过程完成后,核心插件会触发 "updateComplete" 事件。
在寻呼程序代码中,当触发 "updateComplete" 事件时,它会不恰当地更新总行数和总页数,因为正在使用 ajax 并且它只计算当前在 [=] 中的行数27=].
所以基本上,我添加了一个检查以防止在使用 ajax 时重新计算 page/row 计数。
从 GitHub 存储库 master 分支中获取此 latest update for the pager。