How to export all rows from Datatables using Ajax?

前端 未结 12 1207
广开言路
广开言路 2020-11-29 23:38

I am using new feature in Datatables: \"HTML5 export buttons\". I am loading data with Ajax.

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

12条回答
  •  刺人心
    刺人心 (楼主)
    2020-11-29 23:55

    I know this is an old question, however for anyone struggling with this, here's my solution.

    Variables:

    var downloading = false,
        downloadTimestamp = null;
    

    Download button definition:

    buttons: [{
        text: '',
        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 definition:

    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' function:

    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
        }
    }
    

    Server-side:

    if(download == false), then server executes SELECT columns FROM tables WHERE rowNumber BETWEEN firstRow AND lastRow and outputs result for normal display within DataTable.

    if(download == true), then server executes SELECT columns FROM tables and stores all rows formatted as CSV file (or any other file format depending on what Your server environment is capable to produce) server-side for later retrieval by GET request.

    Following is ASP JScript code that I've used server-side:

        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 = []
    

提交回复
热议问题