prosource

Ajax를 사용하여 데이터 테이블에서 모든 행을 내보내려면 어떻게 해야 합니까?

probook 2023. 3. 14. 21:44
반응형

Ajax를 사용하여 데이터 테이블에서 모든 행을 내보내려면 어떻게 해야 합니까?

Datatables의 새로운 기능을 사용하고 있습니다.HTML5 내보내기 버튼"을 클릭합니다.저는 Ajax로 데이터를 로드하고 있습니다.

https://datatables.net/extensions/buttons/examples/html5/simple.html

문제는 현재 표시된 페이지만 내보낸다는 것입니다.

다음과 같이 내보냅니다.

buttons: [
    {
        extend: 'pdfHtml5',
        text: 'PDF',
        exportOptions: {
            "columns": ':visible',
        }
    },
]

모든 행을 내보내려면 어떻게 해야 합니까?

kevinpo라는 유저에게 감사드립니다.서버처리가 켜져 있을 때 jquery datable의 모든 레코드가 Excel로 다운로드되는 방법을 제시했습니다.그의 답변을 바탕으로 서버측 처리를 위한 완전한 내보내기 기능(copy, excel, csv, pdf, print)을 구현했습니다.

에 inside inside inside $(document).ready()하고 이 합니다.action 각 의 :음음음 of of of of of of of of of of 。

/* 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
            }],

바로 그겁니다.이것으로 다운로드가 완료되었습니다.

모든 데이터를 가져오도록 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 문서에 따르면 서버 측을 사용할 때 모든 행을 내보낼 수 있는 방법은 없습니다.

모드에서 를 사용하는 (DataTables)serverSide의 개요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
});

네, 충분히 가능합니다.DataTables 내부에는 buttons.exportData()라는 함수가 있습니다.버튼을 누르면 이 함수가 호출되어 현재 페이지 내용을 반환합니다.현재 필터를 기반으로 모든 서버 측 결과를 가져오도록 해당 함수를 덮어쓸 수 있습니다.그리고 에이잭스 페이지 작성에 사용된 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이 하나의 요청에 대해 현재 필터링에 대한 모든 행을 강제로 요청합니다.수출하다 ''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
    }
}

서버측:

(false == false)인 경우 서버는 테이블에서 SELECT 열을 실행하고 여기서 rowNumber BETHIN firstRow와 lastRow를 실행하여 DataTable에 정상적으로 표시되도록 결과를 출력합니다.

(서버 == true)인 경우 서버는 SELECT 컬럼 FROM 테이블을 실행하고 나중에 GET 요청에 의해 검색할 수 있도록 CSV 파일(또는 생성할 수 있는 서버 환경에 따라 다른 파일 형식) 형식의 모든 행을 서버 측에 저장합니다.

다음은 서버 측에서 사용한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 = []

Larabel 프레임워크를 사용하는 경우는, 이것을 사용할 수 있습니다.

$.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();
});

Selcuk의 답변은 "All"의 값을 미리 수정할 수 있다면 완벽하게 작동합니다.행 수가 변수 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 、 ke dat dat dat dat dat 。서버측 파라미터를 처리하기 위해 조금 수정해야 했지만, 그것이 유일한 걸림돌이었습니다.는 그의: ★★★★★★★★★★★★★★★★★★★★★★」data.length = 2147483647;로로 합니다.data.params[2]= -1;서버측 파라미터를 파라미터 서브어레이에 저장했기 때문입니다.성능을 확인하기 위해 대규모 데이터셋을 사용하여 테스트한 적은 없지만 매우 현명한 솔루션입니다.

이 문제로 어려움을 겪고 있는 사람들을 위해 실제 답변을 올리고 싶었어요.

버튼을 Excel을 할 수 .customizeData버튼 속성

데이터를 가져오고, 반환하고, 마사지하고, 계속 진행하기 위해 서버에 동기 API 호출을 하기 위해 이것을 사용했습니다.아래 코드

                           {
                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 });
                }
            },

@diogenesg 답변 좋아요!

근데 확인했어$.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', ...]
      }
    }
  });

페이지에 숨겨진 추가 테이블을 만들고 모든 데이터를 다운로드하기 위한 버튼을 만들 수 있습니다. 이러한 옵션을 가진 모든 행과 함께 숨겨진 테이블을 데이터 테이블로 만들기 위해 이 코드를 할당할 수 있습니다.

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",
        };

완전한 테이블 이벤트에서 Export Excel 버튼의 트리거를 볼 수 있으며 사용자가 해당 버튼을 클릭하면 자동으로 실행되며 모든 데이터가 포함된 Excel을 얻을 수 있습니다.

효과가 있다

// DataTable 초기화 전 정의

jQuery.fn.DataTable.Api.register('buttons.exportData()', function (options) {
            if (this.context.length) {
                let excelDatas = [];
                //--------------------------Getting - Data-Table-Existing-Prameters--------------------------------//
                let execlParams = this.ajax.params();
                execlParams.export = true; // in database query don't set limit if export is true;
                //--------------------------------------------------------------------------------------------------//
                var jsonResult = $.ajax({
                    "type": "POST",
                    url: URL_load,
                    data: execlParams,
                    success: function (result) {
                        let ReposneData = JSON.parse(result);
                        let stateData = ReposneData.data;
                        (stateData).map((row, index) => {
                            var item = [row.name];
                            excelDatas.push(item);
                        });
                    },
                    async: false
                });
                return {
                    body: excelDatas,
                    header: ['Name']
                };
            }
        });

언급URL : https://stackoverflow.com/questions/32692618/how-to-export-all-rows-from-datatables-using-ajax

반응형