如何使用 Ajax 从数据表中导出所有行?
How to export all rows from Datatables using Ajax?
我正在使用数据表中的新功能:"HTML5 export buttons"。我正在使用 Ajax 加载数据。
https://datatables.net/extensions/buttons/examples/html5/simple.html
问题是它只导出当前显示的页面。
我是这样导出的:
buttons: [
{
extend: 'pdfHtml5',
text: 'PDF',
exportOptions: {
"columns": ':visible',
}
},
]
如何导出所有行?
根据DataTables documentation,当您使用服务器端时无法导出所有行:
Special note on server-side processing: When using DataTables in server-side processing mode (serverSide
) the selector-modifier
has very little effect on the rows selected since all processing (ordering, search etc) is performed at the server. Therefore, the only rows that exist on the client-side are those shown in the table at any one time, and the selector can only select those rows which are on the current page.
我通过向长度菜单添加一个 'ALL' 参数并训练最终用户在执行 PDF(或 XLS)导出之前显示所有记录来解决这个问题:
var table = $('#example').DataTable({
serverSide: true,
ajax: "/your_ajax_url/",
lengthMenu: [[25, 100, -1], [25, 100, "All"]],
pageLength: 25,
buttons: [
{
extend: 'excel',
text: '<span class="fa fa-file-excel-o"></span> Excel Export',
exportOptions: {
modifier: {
search: 'applied',
order: 'applied'
}
}
}
],
// other options
});
这个按钮定义在滚动 table(而不是分页)中对我有用:
{
text: 'PDF',
action: function(e, dt, button, config) {
dt.one('preXhr', function(e, s, data) {
data.length = -1;
}).one('draw', function(e, settings, json, xhr) {
var pdfButtonConfig = $.fn.DataTable.ext.buttons.pdfHtml5;
var addOptions = { exportOptions: { "columns" : ":visible" }};
$.extend(true,pdfButtonConfig,addOptions);
pdfButtonConfig.action(e, dt, button, pdfButtonConfig);
}).draw();
}
}
会强制DataTable一次请求请求当前过滤的所有行。然后它直接调用导出按钮的所需操作。变量 addOptions
可用于更改导出按钮的标准配置。
您可能 运行 遇到问题,但如果您有很多行,因为它们都已加载到 DOM。
我知道这是一个老问题,但是对于任何为此苦苦挣扎的人来说,这是我的解决方案。
变量:
var downloading = false,
downloadTimestamp = null;
下载按钮定义:
buttons: [{
text: '<span class="glyphicon glyphicon-save-file" aria-hidden="true"></span>',
titleAttr: 'CSV',
className: 'downloadCSV',
action: function(e, dt, node, config) {
if (downloading === false) { //if download is in progress, do nothing, else
node.attr('disabled', 'disabled'); //disable download button to prevent multi-click, probably some sort of *busy* indicator is a good idea
downloading = true; //set downloading status to *true*
dt.ajax.reload(); //re-run *DataTables* AJAX query with current filter and sort applied
}
}
}]
Ajax定义:
ajax: {
url: ajaxURL,
type: 'POST',
data: function(data) {
data.timestamp = new Date().getTime(); //add timestamp to data to be sent, it's going to be useful when retrieving produced file server-side
downloadTimestamp = data.timestamp; //save timestamp in local variable for use with GET request when retrieving produced file client-side
if (downloading === true) { //if download button was clicked
data.download = true; //tell server to prepare data for download
downloading = data.draw; //set which *DataTable* draw is actually a request to produce file for download
}
return { data: JSON.stringify(data) }; //pass data to server for processing
}
}
'preDrawCallback'函数:
preDrawCallback: function(settings) {
if (settings.iDraw === downloading) { //if returned *DataTable* draw matches file request draw value
downloading = false; //set downloading flag to false
$('.downloadCSV').removeAttr('disabled'); //enable download button
window.location.href = ajaxURL + '?' + $.param({ ts: downloadTimestamp }); //navigate to AJAX URL with timestamp as parameter to trigger file download. Or You can have hidden IFrame and set its *src* attribute to the address above.
return false; //as it is file request, table should not be re-drawn
}
}
服务器端:
if(download == false),然后服务器执行 SELECT columns FROM tables WHERE rowNumber BETWEEN firstRow AND lastRow并在 DataTable.
中输出正常显示的结果
if(download == true),然后服务器执行 SELECT columns FROM tables 并存储格式为的所有行CSV 文件(或任何其他文件格式,具体取决于您的服务器环境能够生成的内容)服务器端,供以后通过 GET 请求检索。
以下是我在服务器端使用的 ASP JScript 代码:
var timestamp = Number(Request.QueryString('ts')), //if it's a GET request, get timestamp
tableData = {
draw: data.draw,
recordsTotal: 100, //some number static or dynamic
recordsFiltered: 10, //some number static or dynamic
data: []
};
jsonData = String(Request.Form('data')), //if it's POST request, get data sent by *DataTable* AJAX
data = jsonData === 'undefined' || jsonData.length === 0 ? null : JSON.parse(jsonData); //do some error checking (optional)
if(!isNaN(timestamp)) { //check timestamp is valid
var csvTextKey = 'download-' + timestamp, //this is where timestamp value is used (can be any other unique value)
csvText = Session(csvTextKey); //obtain saved CSV text from local server-side storage
if(typeof csvText === 'undefined') { //if CSV text does not exist in local storage, return nothing (or throw error is You wish)
Response.End();
}
//if CSV exists:
Response.ContentType = 'text/csv'; //set response mime type
Response.AddHeader('Content-Disposition', 'attachment; filename=test.csv'); //add header to tell browser that content should be downloaded as file and not displayed
Response.Write(csvText); //send all content to browser
Response.End(); //stop further server-side code execution
}
//if timestamp is not valid then we assume this is POST request, hence data should be either prepared for display or stored for file creation
if(typeof data !== 'object' || data === null) { //do some more clever error checking
throw 'data is not an object or is null';
}
var recordset = data.download === true ? sqlConnection.Execute('SELECT * FROM #FinalTable') : Utilities.prepAndRunSQLQuery('SELECT * FROM #FinalTable WHERE rowId BETWEEN ? AND ?', [data.start, data.start + data.length], //execute SELECT either for display or for file creation
headerRow = [],
sqlHeaderRow = [],
exportData = [];;
if(data.download === true) { //create CSV file (or any other file)
if(!Array.isArray(data.columns)) {
throw 'data.columns is not an array';
}
for(var i = 0, dataColumnsCount = data.columns.length; i < dataColumnsCount; ++i) {
var dataColumn = data.columns[i], //get columns data object sent by client
title = dataColumn.title, //this is custom property set on client-side (not shown in code above)
sqlColumnName = typeof dataColumn.data === 'string' ? dataColumn.data : (typeof dataColumn.data.display === 'string' ? dataColumn.data.display : dataColumn.data['_']); //set SQL table column name variable
if(typeof title === 'string' && typeof sqlColumnName === 'string' && columnNames.indexOf(sqlColumnName) > -1) { //some more error checking
headerRow.push(title);
sqlHeaderRow.push(sqlColumnName);
}
}
exportData.push('"' + headerRow.join('","') + '"'); //add table header row to in CSV file format
}
while(recordset.EOF === false) { //iterate through recordset
if(data.download === true) { //if download flag is set build string containing CSV content
var row = [];
for(var i = 0, count = sqlHeaderRow.length; i < count; ++i) {
row.push(String(recordset.Fields(sqlHeaderRow[i]).Value).replace('"', '""'));
}
exportData.push('"' + row.join('","') + '"');
}
else { //else format data for display
var row = {};
for(var i = 1, fieldsCount = recordset.Fields.Count; i < fieldsCount; ++i) {
var field = recordset.Fields(i),
name = field.Name,
value = field.Value;
row[name] = value;
}
tableData.data.push(row);
}
recordset.MoveNext();
}
if(data.download === true) { //save CSV content in server-side storage
Session('download-' + data.timestamp) = exportData.join('\r\n'); //this is where timestamp value is used (can be any other unique value)
}
Response.Write(JSON.stringify(tableData)); //return data for display, if download flag is set, tableData.data = []
如果我们可以预先确定 "All" 的值,Selcuk 的答案将绝对有效。
假设行数存储在变量 row_count 中。那么
var row_count = $("#row_count").val();
var table = $('#example').DataTable({
serverSide: true,
ajax: "/your_ajax_url/",
lengthMenu: [[25, 100, row_count], [25, 100, "All"]],
pageLength: 25,
buttons: [
{
extend: 'excel',
text: '<span class="fa fa-file-excel-o"></span> Excel Export',
exportOptions: {
modifier: {
search: 'applied',
order: 'applied'
}
}
}
],
// other options
});
是的,完全有可能做到这一点。
在内部,DataTables 有一个名为 buttons.exportData() 的函数。当您按下按钮时,将调用此函数并 returns 当前页面内容。
您可以覆盖该函数,以便它根据当前过滤器提取所有服务器端结果。并调用用于 ajax 分页的相同 url。
您在初始化 table 之前覆盖它。代码如下:
$(document).ready(function() {
jQuery.fn.DataTable.Api.register( 'buttons.exportData()', function ( options ) {
if ( this.context.length ) {
var jsonResult = $.ajax({
url: 'myServerSide.json?page=all',
data: {search: $(#search).val()},
success: function (result) {
//Do nothing
},
async: false
});
return {body: jsonResult.responseJSON.data, header: $("#myTable thead tr th").map(function() { return this.innerHTML; }).get()};
}
} );
$("#myTable ").DataTable(
{
"dom": 'lBrtip',
"pageLength": 5,
"buttons": ['csv','print', 'excel', 'pdf'],
"processing": true,
"serverSide": true,
"ajax": {
"url": "myServerSide.json",
"type": 'GET',
"data": {search: $(#search).val()}
}
}
});
您需要告诉 AJAX 函数获取所有数据,然后进行导出但取消实际绘制,这样所有数据就不会加载到 DOM 中。不过,DataTables API 的完整数据仍将存在于内存中,因此您需要将其刷新为导出前的状态。
var oldExportAction = function (self, e, dt, button, config) {
if (button[0].className.indexOf('buttons-excel') >= 0) {
if ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config)) {
$.fn.dataTable.ext.buttons.excelHtml5.action.call(self, e, dt, button, config);
}
else {
$.fn.dataTable.ext.buttons.excelFlash.action.call(self, e, dt, button, config);
}
} else if (button[0].className.indexOf('buttons-print') >= 0) {
$.fn.dataTable.ext.buttons.print.action(e, dt, button, config);
}
};
var newExportAction = function (e, dt, button, config) {
var self = this;
var oldStart = dt.settings()[0]._iDisplayStart;
dt.one('preXhr', function (e, s, data) {
// Just this once, load all data from the server...
data.start = 0;
data.length = 2147483647;
dt.one('preDraw', function (e, settings) {
// Call the original action function
oldExportAction(self, e, dt, button, config);
dt.one('preXhr', function (e, s, data) {
// DataTables thinks the first item displayed is index 0, but we're not drawing that.
// Set the property to what it was before exporting.
settings._iDisplayStart = oldStart;
data.start = oldStart;
});
// Reload the grid with the original page. Otherwise, API functions like table.cell(this) don't work properly.
setTimeout(dt.ajax.reload, 0);
// Prevent rendering of the full data to the DOM
return false;
});
});
// Requery the server with the new one-time export settings
dt.ajax.reload();
};
和:
buttons: [
{
extend: 'excel',
action: newExportAction
},
我使用的是数据表版本:1.10.15,@kevenpo 的回答有效。我不得不稍微修改它以处理我们的服务器端参数,但这是唯一的绊脚石。我将他的行:data.length = 2147483647;
更改为 data.params[2]= -1;
因为我们将服务器端参数存储在 params 子数组中。我还没有用非常大的数据集测试它以查看性能,但这是一个非常聪明的解决方案。
只是想 post 为遇到此问题的人们提供一个实际的答案。
如果您使用 excel 按钮导出,您可以在导出前使用 customizeData
按钮 属性 格式化要发送到 excel 的数据。
我用它对我的服务器进行同步 api 调用以获取数据,return 它,处理它,然后让它继续它的方式。下面的代码。
{
extend: 'excel',
customizeData: function (p)
{
//get the params for the last datatables ajax call
var params = JSON.parse(options.dataTable.ajax.params());
//flag to tell the server to ignore paging info and get everything that matches the filter
params.export = true;
UC.Api(options.api.read.getHook(), params, function (data)
{
p.body = new Array();
$.each(data.data, function (i, d)
{
var item = [d.serial, UC.FormatDateToLocal(d.meta.Date), d.transmission.title, d.transmission.type, d.transmission.information];
p.body.push(item);
});
}, null, { async: false });
}
},
非常感谢用户“kevinpo”。他给出了当 服务器端处理开启 时如何将 jquery 数据表中的所有记录下载为 excel 的方法。
根据他的回答,我在这里为 服务器端实现了完整的导出功能(copy、excel、csv、pdf、print)处理.
在 $(document).ready()
中定义以下函数并在每个导出按钮的 action
上调用此函数,如下所示:
/* For Export Buttons available inside jquery-datatable "server side processing" - Start
- due to "server side processing" jquery datatble doesn't support all data to be exported
- below function makes the datatable to export all records when "server side processing" is on */
function newexportaction(e, dt, button, config) {
var self = this;
var oldStart = dt.settings()[0]._iDisplayStart;
dt.one('preXhr', function (e, s, data) {
// Just this once, load all data from the server...
data.start = 0;
data.length = 2147483647;
dt.one('preDraw', function (e, settings) {
// Call the original action function
if (button[0].className.indexOf('buttons-copy') >= 0) {
$.fn.dataTable.ext.buttons.copyHtml5.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-excel') >= 0) {
$.fn.dataTable.ext.buttons.excelHtml5.available(dt, config) ?
$.fn.dataTable.ext.buttons.excelHtml5.action.call(self, e, dt, button, config) :
$.fn.dataTable.ext.buttons.excelFlash.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-csv') >= 0) {
$.fn.dataTable.ext.buttons.csvHtml5.available(dt, config) ?
$.fn.dataTable.ext.buttons.csvHtml5.action.call(self, e, dt, button, config) :
$.fn.dataTable.ext.buttons.csvFlash.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-pdf') >= 0) {
$.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config) ?
$.fn.dataTable.ext.buttons.pdfHtml5.action.call(self, e, dt, button, config) :
$.fn.dataTable.ext.buttons.pdfFlash.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-print') >= 0) {
$.fn.dataTable.ext.buttons.print.action(e, dt, button, config);
}
dt.one('preXhr', function (e, s, data) {
// DataTables thinks the first item displayed is index 0, but we're not drawing that.
// Set the property to what it was before exporting.
settings._iDisplayStart = oldStart;
data.start = oldStart;
});
// Reload the grid with the original page. Otherwise, API functions like table.cell(this) don't work properly.
setTimeout(dt.ajax.reload, 0);
// Prevent rendering of the full data to the DOM
return false;
});
});
// Requery the server with the new one-time export settings
dt.ajax.reload();
};
//For Export Buttons available inside jquery-datatable "server side processing" - End
对于按钮,定义如下
"buttons": [{
"extend": 'copy',
"text": '<i class="fa fa-files-o" style="color: green;"></i>',
"titleAttr": 'Copy',
"action": newexportaction
},
{
"extend": 'excel',
"text": '<i class="fa fa-file-excel-o" style="color: green;"></i>',
"titleAttr": 'Excel',
"action": newexportaction
},
{
"extend": 'csv',
"text": '<i class="fa fa-file-text-o" style="color: green;"></i>',
"titleAttr": 'CSV',
"action": newexportaction
},
{
"extend": 'pdf',
"text": '<i class="fa fa-file-pdf-o" style="color: green;"></i>',
"titleAttr": 'PDF',
"action": newexportaction
},
{
"extend": 'print',
"text": '<i class="fa fa-print" style="color: green;"></i>',
"titleAttr": 'Print',
"action": newexportaction
}],
就是这样。现在您的下载已准备就绪。
如果你使用Laravel框架,你可以使用这个....
$.fn.DataTable.Api.register( 'buttons.exportData()', function( options ) {
if(this.context.length) {
var src_keyword = $('.dataTables_filter input').val();
// make columns for sorting
var columns = [];
$.each(this.context[0].aoColumns, function(key, value) {
columns.push({
'data' : value.data,
'name' : value.name,
'searchable' : value.bSearchable,
'orderable' : value.bSortable
});
});
// make option for sorting
var order = [];
$.each(this.context[0].aaSorting, function(key, value) {
order.push({
'column' : value[0],
'dir' : value[1]
});
});
// make value for search
var search = {
'value' : this.context[0].oPreviousSearch.sSearch,
'regex' : this.context[0].oPreviousSearch.bRegex
};
var items = [];
var status = $('#status').val();
$.ajax({
url: "server_side_url",
data: { columns: columns, order: order, search: search, status: status, page: 'all' }
success: function (result) {
$.each(result.data, function(key, value) {
var item = [];
item.push(key+1);
item.push(value.username);
item.push(value.email);
item.push(value.created_at);
item.push(value.status);
items.push(item);
});
},
async: false
});
return {
body: items,
// skip actions header
header: $("#user_table thead tr th").map(function() {
if(this.innerHTML!='Actions')
return this.innerHTML;
}).get()
};
}
});
var user_table = $('#user_table').DataTable({
dom: 'Bfrtip',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
],
"oSearch": {"bSmart": false},
processing: true,
serverSide: true,
ajax: {
url: "server_side_url",
type: 'GET',
data: function (d) {
d.status = ""; // when onload make status as empty to get all users
}
},
columns: [
{data: 'DT_RowIndex', name: 'DT_RowIndex'},
{data: 'username', name: 'username'},
{data: 'email', name: 'email'},
{data: 'created_at', name: 'created_at'},
{data: 'status', name: 'status'},
{data: 'actions', name: 'actions', orderable: false, searchable: false},
],
});
// filter users with status
$('#status').change(function() {
user_table.draw();
});
@diogenesgg 回答的很好!
但我查了 $.fn.DataTable.Api.register
不支持 Promise
所以,我先去取了数据。
const {data} = await selectDailyConnectStatistics({
page: 1,
limit: 99999999
}))
excelDatas = data.list
$("#table").DataTable().button('.buttons-excel').trigger();
第二次触发excel导出。
let excelDatas = []
$.fn.DataTable.Api.register('buttons.exportData()', function(options) {
if (this.context.length ) {
return {
body: _.map(excelDatas, v=> [v.data, ...]),
header: ['colum header name', ...]
}
}
});
您可以在您的页面中创建一个额外的隐藏项 table,然后创建一个用于下载所有数据的按钮,将此代码分配给隐藏 table 作为数据table,所有行都包含这些选项
var options = {
"processing": true,
"serverSide": true,
"ajax": fullbase,
"language": {
"search": "Buscar: ",
"zeroRecords": "Datos no encontrados."
},
"initComplete": function(settings, json) {
$(".buttons-excel").click();
},
"iDisplayLength": 100000,
lengthMenu: [[10,25,50,100, 100000], [10,25,50, 100, "All"]],
"buttons": [{
extend : 'excel',
exportOptions : {
order : 'current',
page : 'all',
search : 'none'
}
}],
"dom": "Blfrtip",
};
您可以在完成 table 事件中看到导出 excel 按钮的触发器,并且会 运行 自动为用户
当用户点击那个按钮然后得到一个 excel 与所有数据
我正在使用数据表中的新功能:"HTML5 export buttons"。我正在使用 Ajax 加载数据。
https://datatables.net/extensions/buttons/examples/html5/simple.html
问题是它只导出当前显示的页面。
我是这样导出的:
buttons: [
{
extend: 'pdfHtml5',
text: 'PDF',
exportOptions: {
"columns": ':visible',
}
},
]
如何导出所有行?
根据DataTables documentation,当您使用服务器端时无法导出所有行:
Special note on server-side processing: When using DataTables in server-side processing mode (
serverSide
) theselector-modifier
has very little effect on the rows selected since all processing (ordering, search etc) is performed at the server. Therefore, the only rows that exist on the client-side are those shown in the table at any one time, and the selector can only select those rows which are on the current page.
我通过向长度菜单添加一个 'ALL' 参数并训练最终用户在执行 PDF(或 XLS)导出之前显示所有记录来解决这个问题:
var table = $('#example').DataTable({
serverSide: true,
ajax: "/your_ajax_url/",
lengthMenu: [[25, 100, -1], [25, 100, "All"]],
pageLength: 25,
buttons: [
{
extend: 'excel',
text: '<span class="fa fa-file-excel-o"></span> Excel Export',
exportOptions: {
modifier: {
search: 'applied',
order: 'applied'
}
}
}
],
// other options
});
这个按钮定义在滚动 table(而不是分页)中对我有用:
{
text: 'PDF',
action: function(e, dt, button, config) {
dt.one('preXhr', function(e, s, data) {
data.length = -1;
}).one('draw', function(e, settings, json, xhr) {
var pdfButtonConfig = $.fn.DataTable.ext.buttons.pdfHtml5;
var addOptions = { exportOptions: { "columns" : ":visible" }};
$.extend(true,pdfButtonConfig,addOptions);
pdfButtonConfig.action(e, dt, button, pdfButtonConfig);
}).draw();
}
}
会强制DataTable一次请求请求当前过滤的所有行。然后它直接调用导出按钮的所需操作。变量 addOptions
可用于更改导出按钮的标准配置。
您可能 运行 遇到问题,但如果您有很多行,因为它们都已加载到 DOM。
我知道这是一个老问题,但是对于任何为此苦苦挣扎的人来说,这是我的解决方案。
变量:
var downloading = false,
downloadTimestamp = null;
下载按钮定义:
buttons: [{
text: '<span class="glyphicon glyphicon-save-file" aria-hidden="true"></span>',
titleAttr: 'CSV',
className: 'downloadCSV',
action: function(e, dt, node, config) {
if (downloading === false) { //if download is in progress, do nothing, else
node.attr('disabled', 'disabled'); //disable download button to prevent multi-click, probably some sort of *busy* indicator is a good idea
downloading = true; //set downloading status to *true*
dt.ajax.reload(); //re-run *DataTables* AJAX query with current filter and sort applied
}
}
}]
Ajax定义:
ajax: {
url: ajaxURL,
type: 'POST',
data: function(data) {
data.timestamp = new Date().getTime(); //add timestamp to data to be sent, it's going to be useful when retrieving produced file server-side
downloadTimestamp = data.timestamp; //save timestamp in local variable for use with GET request when retrieving produced file client-side
if (downloading === true) { //if download button was clicked
data.download = true; //tell server to prepare data for download
downloading = data.draw; //set which *DataTable* draw is actually a request to produce file for download
}
return { data: JSON.stringify(data) }; //pass data to server for processing
}
}
'preDrawCallback'函数:
preDrawCallback: function(settings) {
if (settings.iDraw === downloading) { //if returned *DataTable* draw matches file request draw value
downloading = false; //set downloading flag to false
$('.downloadCSV').removeAttr('disabled'); //enable download button
window.location.href = ajaxURL + '?' + $.param({ ts: downloadTimestamp }); //navigate to AJAX URL with timestamp as parameter to trigger file download. Or You can have hidden IFrame and set its *src* attribute to the address above.
return false; //as it is file request, table should not be re-drawn
}
}
服务器端:
if(download == false),然后服务器执行 SELECT columns FROM tables WHERE rowNumber BETWEEN firstRow AND lastRow并在 DataTable.
中输出正常显示的结果if(download == true),然后服务器执行 SELECT columns FROM tables 并存储格式为的所有行CSV 文件(或任何其他文件格式,具体取决于您的服务器环境能够生成的内容)服务器端,供以后通过 GET 请求检索。
以下是我在服务器端使用的 ASP JScript 代码:
var timestamp = Number(Request.QueryString('ts')), //if it's a GET request, get timestamp
tableData = {
draw: data.draw,
recordsTotal: 100, //some number static or dynamic
recordsFiltered: 10, //some number static or dynamic
data: []
};
jsonData = String(Request.Form('data')), //if it's POST request, get data sent by *DataTable* AJAX
data = jsonData === 'undefined' || jsonData.length === 0 ? null : JSON.parse(jsonData); //do some error checking (optional)
if(!isNaN(timestamp)) { //check timestamp is valid
var csvTextKey = 'download-' + timestamp, //this is where timestamp value is used (can be any other unique value)
csvText = Session(csvTextKey); //obtain saved CSV text from local server-side storage
if(typeof csvText === 'undefined') { //if CSV text does not exist in local storage, return nothing (or throw error is You wish)
Response.End();
}
//if CSV exists:
Response.ContentType = 'text/csv'; //set response mime type
Response.AddHeader('Content-Disposition', 'attachment; filename=test.csv'); //add header to tell browser that content should be downloaded as file and not displayed
Response.Write(csvText); //send all content to browser
Response.End(); //stop further server-side code execution
}
//if timestamp is not valid then we assume this is POST request, hence data should be either prepared for display or stored for file creation
if(typeof data !== 'object' || data === null) { //do some more clever error checking
throw 'data is not an object or is null';
}
var recordset = data.download === true ? sqlConnection.Execute('SELECT * FROM #FinalTable') : Utilities.prepAndRunSQLQuery('SELECT * FROM #FinalTable WHERE rowId BETWEEN ? AND ?', [data.start, data.start + data.length], //execute SELECT either for display or for file creation
headerRow = [],
sqlHeaderRow = [],
exportData = [];;
if(data.download === true) { //create CSV file (or any other file)
if(!Array.isArray(data.columns)) {
throw 'data.columns is not an array';
}
for(var i = 0, dataColumnsCount = data.columns.length; i < dataColumnsCount; ++i) {
var dataColumn = data.columns[i], //get columns data object sent by client
title = dataColumn.title, //this is custom property set on client-side (not shown in code above)
sqlColumnName = typeof dataColumn.data === 'string' ? dataColumn.data : (typeof dataColumn.data.display === 'string' ? dataColumn.data.display : dataColumn.data['_']); //set SQL table column name variable
if(typeof title === 'string' && typeof sqlColumnName === 'string' && columnNames.indexOf(sqlColumnName) > -1) { //some more error checking
headerRow.push(title);
sqlHeaderRow.push(sqlColumnName);
}
}
exportData.push('"' + headerRow.join('","') + '"'); //add table header row to in CSV file format
}
while(recordset.EOF === false) { //iterate through recordset
if(data.download === true) { //if download flag is set build string containing CSV content
var row = [];
for(var i = 0, count = sqlHeaderRow.length; i < count; ++i) {
row.push(String(recordset.Fields(sqlHeaderRow[i]).Value).replace('"', '""'));
}
exportData.push('"' + row.join('","') + '"');
}
else { //else format data for display
var row = {};
for(var i = 1, fieldsCount = recordset.Fields.Count; i < fieldsCount; ++i) {
var field = recordset.Fields(i),
name = field.Name,
value = field.Value;
row[name] = value;
}
tableData.data.push(row);
}
recordset.MoveNext();
}
if(data.download === true) { //save CSV content in server-side storage
Session('download-' + data.timestamp) = exportData.join('\r\n'); //this is where timestamp value is used (can be any other unique value)
}
Response.Write(JSON.stringify(tableData)); //return data for display, if download flag is set, tableData.data = []
如果我们可以预先确定 "All" 的值,Selcuk 的答案将绝对有效。 假设行数存储在变量 row_count 中。那么
var row_count = $("#row_count").val();
var table = $('#example').DataTable({
serverSide: true,
ajax: "/your_ajax_url/",
lengthMenu: [[25, 100, row_count], [25, 100, "All"]],
pageLength: 25,
buttons: [
{
extend: 'excel',
text: '<span class="fa fa-file-excel-o"></span> Excel Export',
exportOptions: {
modifier: {
search: 'applied',
order: 'applied'
}
}
}
],
// other options
});
是的,完全有可能做到这一点。 在内部,DataTables 有一个名为 buttons.exportData() 的函数。当您按下按钮时,将调用此函数并 returns 当前页面内容。 您可以覆盖该函数,以便它根据当前过滤器提取所有服务器端结果。并调用用于 ajax 分页的相同 url。
您在初始化 table 之前覆盖它。代码如下:
$(document).ready(function() {
jQuery.fn.DataTable.Api.register( 'buttons.exportData()', function ( options ) {
if ( this.context.length ) {
var jsonResult = $.ajax({
url: 'myServerSide.json?page=all',
data: {search: $(#search).val()},
success: function (result) {
//Do nothing
},
async: false
});
return {body: jsonResult.responseJSON.data, header: $("#myTable thead tr th").map(function() { return this.innerHTML; }).get()};
}
} );
$("#myTable ").DataTable(
{
"dom": 'lBrtip',
"pageLength": 5,
"buttons": ['csv','print', 'excel', 'pdf'],
"processing": true,
"serverSide": true,
"ajax": {
"url": "myServerSide.json",
"type": 'GET',
"data": {search: $(#search).val()}
}
}
});
您需要告诉 AJAX 函数获取所有数据,然后进行导出但取消实际绘制,这样所有数据就不会加载到 DOM 中。不过,DataTables API 的完整数据仍将存在于内存中,因此您需要将其刷新为导出前的状态。
var oldExportAction = function (self, e, dt, button, config) {
if (button[0].className.indexOf('buttons-excel') >= 0) {
if ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config)) {
$.fn.dataTable.ext.buttons.excelHtml5.action.call(self, e, dt, button, config);
}
else {
$.fn.dataTable.ext.buttons.excelFlash.action.call(self, e, dt, button, config);
}
} else if (button[0].className.indexOf('buttons-print') >= 0) {
$.fn.dataTable.ext.buttons.print.action(e, dt, button, config);
}
};
var newExportAction = function (e, dt, button, config) {
var self = this;
var oldStart = dt.settings()[0]._iDisplayStart;
dt.one('preXhr', function (e, s, data) {
// Just this once, load all data from the server...
data.start = 0;
data.length = 2147483647;
dt.one('preDraw', function (e, settings) {
// Call the original action function
oldExportAction(self, e, dt, button, config);
dt.one('preXhr', function (e, s, data) {
// DataTables thinks the first item displayed is index 0, but we're not drawing that.
// Set the property to what it was before exporting.
settings._iDisplayStart = oldStart;
data.start = oldStart;
});
// Reload the grid with the original page. Otherwise, API functions like table.cell(this) don't work properly.
setTimeout(dt.ajax.reload, 0);
// Prevent rendering of the full data to the DOM
return false;
});
});
// Requery the server with the new one-time export settings
dt.ajax.reload();
};
和:
buttons: [
{
extend: 'excel',
action: newExportAction
},
我使用的是数据表版本:1.10.15,@kevenpo 的回答有效。我不得不稍微修改它以处理我们的服务器端参数,但这是唯一的绊脚石。我将他的行:data.length = 2147483647;
更改为 data.params[2]= -1;
因为我们将服务器端参数存储在 params 子数组中。我还没有用非常大的数据集测试它以查看性能,但这是一个非常聪明的解决方案。
只是想 post 为遇到此问题的人们提供一个实际的答案。
如果您使用 excel 按钮导出,您可以在导出前使用 customizeData
按钮 属性 格式化要发送到 excel 的数据。
我用它对我的服务器进行同步 api 调用以获取数据,return 它,处理它,然后让它继续它的方式。下面的代码。
{
extend: 'excel',
customizeData: function (p)
{
//get the params for the last datatables ajax call
var params = JSON.parse(options.dataTable.ajax.params());
//flag to tell the server to ignore paging info and get everything that matches the filter
params.export = true;
UC.Api(options.api.read.getHook(), params, function (data)
{
p.body = new Array();
$.each(data.data, function (i, d)
{
var item = [d.serial, UC.FormatDateToLocal(d.meta.Date), d.transmission.title, d.transmission.type, d.transmission.information];
p.body.push(item);
});
}, null, { async: false });
}
},
非常感谢用户“kevinpo”。他给出了当 服务器端处理开启 时如何将 jquery 数据表中的所有记录下载为 excel 的方法。 根据他的回答,我在这里为 服务器端实现了完整的导出功能(copy、excel、csv、pdf、print)处理.
在 $(document).ready()
中定义以下函数并在每个导出按钮的 action
上调用此函数,如下所示:
/* For Export Buttons available inside jquery-datatable "server side processing" - Start
- due to "server side processing" jquery datatble doesn't support all data to be exported
- below function makes the datatable to export all records when "server side processing" is on */
function newexportaction(e, dt, button, config) {
var self = this;
var oldStart = dt.settings()[0]._iDisplayStart;
dt.one('preXhr', function (e, s, data) {
// Just this once, load all data from the server...
data.start = 0;
data.length = 2147483647;
dt.one('preDraw', function (e, settings) {
// Call the original action function
if (button[0].className.indexOf('buttons-copy') >= 0) {
$.fn.dataTable.ext.buttons.copyHtml5.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-excel') >= 0) {
$.fn.dataTable.ext.buttons.excelHtml5.available(dt, config) ?
$.fn.dataTable.ext.buttons.excelHtml5.action.call(self, e, dt, button, config) :
$.fn.dataTable.ext.buttons.excelFlash.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-csv') >= 0) {
$.fn.dataTable.ext.buttons.csvHtml5.available(dt, config) ?
$.fn.dataTable.ext.buttons.csvHtml5.action.call(self, e, dt, button, config) :
$.fn.dataTable.ext.buttons.csvFlash.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-pdf') >= 0) {
$.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config) ?
$.fn.dataTable.ext.buttons.pdfHtml5.action.call(self, e, dt, button, config) :
$.fn.dataTable.ext.buttons.pdfFlash.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-print') >= 0) {
$.fn.dataTable.ext.buttons.print.action(e, dt, button, config);
}
dt.one('preXhr', function (e, s, data) {
// DataTables thinks the first item displayed is index 0, but we're not drawing that.
// Set the property to what it was before exporting.
settings._iDisplayStart = oldStart;
data.start = oldStart;
});
// Reload the grid with the original page. Otherwise, API functions like table.cell(this) don't work properly.
setTimeout(dt.ajax.reload, 0);
// Prevent rendering of the full data to the DOM
return false;
});
});
// Requery the server with the new one-time export settings
dt.ajax.reload();
};
//For Export Buttons available inside jquery-datatable "server side processing" - End
对于按钮,定义如下
"buttons": [{
"extend": 'copy',
"text": '<i class="fa fa-files-o" style="color: green;"></i>',
"titleAttr": 'Copy',
"action": newexportaction
},
{
"extend": 'excel',
"text": '<i class="fa fa-file-excel-o" style="color: green;"></i>',
"titleAttr": 'Excel',
"action": newexportaction
},
{
"extend": 'csv',
"text": '<i class="fa fa-file-text-o" style="color: green;"></i>',
"titleAttr": 'CSV',
"action": newexportaction
},
{
"extend": 'pdf',
"text": '<i class="fa fa-file-pdf-o" style="color: green;"></i>',
"titleAttr": 'PDF',
"action": newexportaction
},
{
"extend": 'print',
"text": '<i class="fa fa-print" style="color: green;"></i>',
"titleAttr": 'Print',
"action": newexportaction
}],
就是这样。现在您的下载已准备就绪。
如果你使用Laravel框架,你可以使用这个....
$.fn.DataTable.Api.register( 'buttons.exportData()', function( options ) {
if(this.context.length) {
var src_keyword = $('.dataTables_filter input').val();
// make columns for sorting
var columns = [];
$.each(this.context[0].aoColumns, function(key, value) {
columns.push({
'data' : value.data,
'name' : value.name,
'searchable' : value.bSearchable,
'orderable' : value.bSortable
});
});
// make option for sorting
var order = [];
$.each(this.context[0].aaSorting, function(key, value) {
order.push({
'column' : value[0],
'dir' : value[1]
});
});
// make value for search
var search = {
'value' : this.context[0].oPreviousSearch.sSearch,
'regex' : this.context[0].oPreviousSearch.bRegex
};
var items = [];
var status = $('#status').val();
$.ajax({
url: "server_side_url",
data: { columns: columns, order: order, search: search, status: status, page: 'all' }
success: function (result) {
$.each(result.data, function(key, value) {
var item = [];
item.push(key+1);
item.push(value.username);
item.push(value.email);
item.push(value.created_at);
item.push(value.status);
items.push(item);
});
},
async: false
});
return {
body: items,
// skip actions header
header: $("#user_table thead tr th").map(function() {
if(this.innerHTML!='Actions')
return this.innerHTML;
}).get()
};
}
});
var user_table = $('#user_table').DataTable({
dom: 'Bfrtip',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
],
"oSearch": {"bSmart": false},
processing: true,
serverSide: true,
ajax: {
url: "server_side_url",
type: 'GET',
data: function (d) {
d.status = ""; // when onload make status as empty to get all users
}
},
columns: [
{data: 'DT_RowIndex', name: 'DT_RowIndex'},
{data: 'username', name: 'username'},
{data: 'email', name: 'email'},
{data: 'created_at', name: 'created_at'},
{data: 'status', name: 'status'},
{data: 'actions', name: 'actions', orderable: false, searchable: false},
],
});
// filter users with status
$('#status').change(function() {
user_table.draw();
});
@diogenesgg 回答的很好!
但我查了 $.fn.DataTable.Api.register
不支持 Promise
所以,我先去取了数据。
const {data} = await selectDailyConnectStatistics({
page: 1,
limit: 99999999
}))
excelDatas = data.list
$("#table").DataTable().button('.buttons-excel').trigger();
第二次触发excel导出。
let excelDatas = []
$.fn.DataTable.Api.register('buttons.exportData()', function(options) {
if (this.context.length ) {
return {
body: _.map(excelDatas, v=> [v.data, ...]),
header: ['colum header name', ...]
}
}
});
您可以在您的页面中创建一个额外的隐藏项 table,然后创建一个用于下载所有数据的按钮,将此代码分配给隐藏 table 作为数据table,所有行都包含这些选项
var options = {
"processing": true,
"serverSide": true,
"ajax": fullbase,
"language": {
"search": "Buscar: ",
"zeroRecords": "Datos no encontrados."
},
"initComplete": function(settings, json) {
$(".buttons-excel").click();
},
"iDisplayLength": 100000,
lengthMenu: [[10,25,50,100, 100000], [10,25,50, 100, "All"]],
"buttons": [{
extend : 'excel',
exportOptions : {
order : 'current',
page : 'all',
search : 'none'
}
}],
"dom": "Blfrtip",
};
您可以在完成 table 事件中看到导出 excel 按钮的触发器,并且会 运行 自动为用户 当用户点击那个按钮然后得到一个 excel 与所有数据