Datatablesの新機能「HTML5エクスポートボタン」を使用しています。 Ajaxでデータをロードしています。
https://datatables.net/extensions/buttons/examples/html5/simple.html
問題は、現在表示されているページのみをエクスポートすることです。
私はこのようにエクスポートしています:
buttons: [
{
extend: 'pdfHtml5',
text: 'PDF',
exportOptions: {
"columns": ':visible',
}
},
]
すべての行をエクスポートするにはどうすればよいですか?
DataTables documentation によると、サーバー側を使用しているときにすべての行をエクスポートする方法はありません。
サーバー側の処理に関する特記事項:サーバー側の処理モード(
serverSide
)でDataTablesを使用する場合、selector-modifier
は、すべての処理(順序付け、検索など)がサーバーで実行されるため、選択した行にはほとんど影響しません。したがって、クライアント側に存在する行は、常にテーブルに表示される行のみであり、セレクターは現在のページにある行のみを選択できます。
これを回避するには、長さメニューに「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
});
すべてのデータを取得するように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
},
はい、この作品を作ることは完全に可能です。内部的に、DataTablesには、buttons.exportData()という関数があります。ボタンを押すと、この関数が呼び出され、現在のページコンテンツが返されます。この関数を上書きして、現在のフィルターに基づいてすべてのサーバー側の結果を取得することができます。そして、ajaxページネーションに使用されるのと同じURLを呼び出します。
テーブルを初期化する前に上書きします。コードは次のとおりです。
$(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()}
}
}
});
このボタンの定義は、(ページングの代わりに)スクロールテーブルで機能しました。
{
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は、1つの要求に対して現在のフィルタリングのすべての行を要求します。次に、[エクスポート]ボタンの目的のアクションを直接呼び出します。変数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)、次にサーバーが実行しますテーブルから列を選択しますWHERE rowNumber BETWEEN firstRow AND lastRowおよびDataTable内の通常表示の結果を出力します。
if(download == true)、サーバーは実行しますSELECT FROM 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 = []
ユーザー「kevinpo」に感謝します。 サーバー側の処理がオンの場合、jquery datatableのすべてのレコードをExcelとしてダウンロードする方法を提供しました。彼の答えに基づいて、ここで私は完全なエクスポート機能を実装しています(コピー、Excel、csv、pdf、印刷)サーバー側処理。
内部$(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
}
],
@diogenesggの答えは良いです!
しかし、私は$.fn.DataTable.Api.register
サポートしないPromise
そこで、最初にデータを取得しました。
const {data} = await selectDailyConnectStatistics({
page: 1,
limit: 99999999
}))
excelDatas = data.list
$("#table").DataTable().button('.buttons-Excel').trigger();
2番目のトリガー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', ...]
}
}
});
Laravelフレームワークを使用する場合、これを使用できます。..
$.fn.DataTable.Api.register( 'buttons.exportData()', function( options ) {
if(this.context.length) {
var src_keyword = $('.dataTables_filter input').val();
var items = [];
$.ajax({
url: "server_side_url",
success: function (result) {
var k = 1;
$.each(result.data, function(key, value) {
var item = [];
item.Push(k);
item.Push(value.username);
item.Push(value.email);
item.Push(value.created_at);
item.Push(value.status);
// filter search with regex
arr = $.map(item, function (value) {
var search = new RegExp(src_keyword, "gi");
if(value.toString().match(search)) return value;
return null;
});
if(!src_keyword || (src_keyword && arr.length)) {
items.Push(item);
k++;
}
});
},
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 = "";
}
},
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},
],
});
セルチュクの答えは、「すべて」の値を事前に修正できれば、まったく問題なく機能します。行数が変数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バージョン:1.10.15を使用していますが、@ kevenpoの答えが得られました。サーバー側のパラメーターを処理するために少し変更する必要がありましたが、それが唯一の障害です。私は彼の行を変更しました:data.length = 2147483647;
からdata.params[2]= -1;
サーバー側パラメーターをparamsサブ配列に格納したため。性能を確認するために非常に大きなデータセットでまだテストしていませんが、これは非常に賢い解決策です。