I have created a web page using bootstrap/thymeleaf where I show some data tables using Ajax. And I have the buttons to export to CSV, but what I need is to generate a temporary file from this datatable and get the path to my controller when the datatable is already loaded with the data using a button.
So I need a way to do that creating a new function, but I don't really know how to do it. May be without call again my sql repository because tables are very large.
JavaScript Code
function mostrarMaticulaEstudiant(data) {
var url = "/9avaldoval/administracio/cercarMaticulaEstudiant?idEdicio=" + data;
dataTableMatriculaEstudiant(url);
}
function dataTableMatriculaEstudiant(url) {
var columns;
var columnsConfig;
var columnsFiltres;
columns = crearColumnesTaulaMatriculaEstudiant();
//columnsConfig = configurarColumnaBotonsEstudis(columns.length);
var sorting = [[0, "asc"]];
var htmlTable = crearTaulaHtmlMatriculaEstudiant(14);
$('#divTaula').html(htmlTable);
var table = $('#taulaMatriculaEstudiant').DataTable({
scrollX: true,
processing: false,
ajaxSource: url,
fnServerData: function(sSource, aoData, fnCallback) {
aoData = $("#formAdmBlue").serializeArray();
$.ajax({
"dataType": 'json',
"type": "POST",
"url": sSource,
"data": aoData,
"success": fnCallback
});
},
columns: columns,
columnDefs: columnsConfig,
sorting: sorting,
language: {
"lengthMenu": "Mostra _MENU_ files per pàgina",
"search": "Filtre: ",
"zeroRecords": "Sense resultats",
"info": "Pàgina _PAGE_ de _PAGES_",
"infoEmpty": "Files no trobades a la cerca",
"infoFiltered": "(filtrat de _MAX_ files totals)",
"sProcessing": "<img src='/9avaldoval/img/loading_gear.gif' width='48px' height='48px'>",
"paginate": {
"next": "<span class='oi oi-chevron-right'></span>",
"previous": "<span class='oi oi-chevron-left'></span>"
}
},
dom: "<'row'<'col-sm-12 col-md-4'B><'col-sm-12 col-md-4'l><'col-sm-12 col-md-4'f>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
buttons: ['copy', 'excel', 'pdf'],
error: function() {
alert("No s'ha pogut obtenir la informació");
}
});
}
function crearTaulaHtmlMatriculaEstudiant(numColumnes) {
var htmlTableOpen = '<table style="width: 100%;" cellpadding="0" cellspacing="0" border="0" class="table table-hover" id="taulaMatriculaEstudiant"><thead>';
var htmlTableHeaderRow = '<tr>';
var htmlTh = '<th></th>';
for (var i = 0; i < numColumnes; i++) {
htmlTableHeaderRow = htmlTableHeaderRow + htmlTh;
}
htmlTableHeaderRow = htmlTableHeaderRow + '</tr>';
var htmlTableClose = '</thead></table>';
var htmlTable = htmlTableOpen + htmlTableHeaderRow + htmlTableClose;
return htmlTable;
}
function crearColumnesTaulaMatriculaEstudiant() {
var columns = [];
columns.push({ "sTitle": "IdAssigEdicio", "mData": "IdAssigEdicio", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "IdEdicio", "mData": "IdEdicio", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "IdCodiassigPare", "mData": "IdCodiassigPare", "sWidth": "10%", "className": "text-center", "defaultContent": "" });
columns.push({ "sTitle": "IdUsuariUPF", "mData": "IdUsuariUPF", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "IdCodiAssigFill", "mData": "IdCodiAssigFill", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "IdAssigFill", "mData": "IdAssigFill", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "EsRepetidor", "mData": "EsRepetidor", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "CodiCentreEstudiant", "mData": "CodiCentreEstudiant", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "CentreEstudiant", "mData": "CentreEstudiant", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "EstudiEstudiant", "mData": "EstudiEstudiant", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "CodiEstudiEstudiantL", "mData": "CodiEstudiEstudiantL", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "DescEstudi_es", "mData": "DescEstudi_es", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "DescEstudi_en", "mData": "DescEstudi_en", "sWidth": "10%", "defaultContent": "" });
columns.push({ "sTitle": "DescEstudi_ca", "mData": "DescEstudi_ca", "sWidth": "10%", "defaultContent": "" });
return columns;
}
Controller
#RequestMapping(value = "cercarMaticulaEstudiant", params = "idEdicio")
public #ResponseBody byte[] cercarMaticulaEstudiant(#RequestParam("idEdicio") String idEdicio, Model model)
throws UnsupportedEncodingException, ParseException {
log.debug("***** cercarEdicions AJAX ****");
byte[] dataTableSource = null;
List<BlueMatriculaEstudiant> llistaMatriculaEstudiants;
llistaMatriculaEstudiants = blueMatriculaEstudiantService
.cercarBlueMatriculaEstudiant(Integer.parseInt(idEdicio));
dataTableSource = operacionsService.blueMatriculaEstudiantsToJson(llistaMatriculaEstudiants);
return dataTableSource;
}
HTML/Bootstrap
<div class="col-lg-12"
style="margin-bottom: 40px;">
<br>
<div class="card">
<h5 class="card-header" th:id="llistat"
data-th-text="#{administracio.blue.llistat}"></h5>
<div class="card-body">
<div class="row"
style="padding-left: 10px; padding-right: 10px;">
<div class="col-md-12">
<div id="divTaula"></div>
</div>
</div>
</div>
</div>
</div>
I think the easiest way would be to create the csv files using JS on the client-side.
First of all, you will need to get the data from your DataTable, their documentation shows it could be done like this:
let table = $('#taulaMatriculaEstudiant').DataTable()
let data = table
.rows()
.data()
Now, csv format is basically a text format with separators. So you need to iterate over the rows in data and merge cells to separate text rows, something like this:
let text = '';
data.map( row => text += row.join( ';' ) + '\n' ) // replace ';' with your preferred CSV separator
Then you only need to create a document and download it. To do that I would suggest the usage of filesaver.js:
let blob = new Blob( [text], {type: "text/csv;charset=utf-8"} )
saveAs( blob, 'taulaMatriculaEstudiant.csv' ) // any name with CSV extension
Please note that I have never worked with DataTables, so I might be mistaken about the data structure in which it returns the data from table after .rows().data() (I assumed it returns an array of arrays that represent the cells in the rows). The general approach should be correct.
Edit
However I would not recommend sending data from the browser to the server - just create the correct file on the server side insted. E.g. like this:
#Controller // note it's not #RestController
public class CsvController {
private CommonDataService dataService; // service with your table data logic. Don't forget to add #Service to it
#GetMapping( "/csv/example" )
public void exampleCsv( HttpServletResponse response ) throws IOException {
byte[] processedFile = dataService.getTaulaMatriculaEstudiant(); // prepare your data the same way as your main data controller and create the csv table the way you like it
ContentDisposition disposition = ContentDisposition.builder( "attachment" )
.filename( "taulaMatriculaEstudiant.csv", StandardCharsets.UTF_8 )
.build();
response.setContentType( "text/csv" );
response.setHeader( "Cache-Control", "no-cache" );
response.setHeader( "Expires", "0" );
response.setHeader( "Pragma", "no-cache" );
IOUtils.copy( new ByteArrayInputStream( processedFile ), response.getOutputStream() ); // IOUtils from Apache Commons-IO
}
#Autowired
public void setDataService( CommonDataService dataService ) {
this.dataService = dataService;
}
}
Related
I am trying to load datatable from ajax response and then perform server-side processing. using this example
this is the response I am receiving from server :
{"msg":null,"code":null,"status":null,"result":[{"aNumber":"3224193861","bNumber":"3215910681","dateTime":"2017-06-05 09:44:22.0","duration":778,"imei":"47350901163665"},{"aNumber":"3224193861","bNumber":"3028540439","dateTime":"2017-04-26 18:53:23.0","duration":266,"imei":"31489802062929"}],"draw":1,"limit":1000,"recordsFiltered":13419,"recordsTotal":13419}
this my javascript code to handle ajax and datatable.
function showDataTable(anumber, startdate, enddate) {
var cdrReqParams = {};
cdrReqParams.draw = '1';
cdrReqParams.offset = 0;
cdrReqParams.newRequest = '1';
cdrReqParams.totalRecords = '1';
cdrReqParams.lookInCol = 'aNumber';
cdrReqParams.lookInVal = anumber;
cdrReqParams.fromDate = startdate;
cdrReqParams.toDate = enddate;
var jsonStr = JSON.stringify(cdrReqParams);
console.log(jsonStr);
API.call("http://localhost:8050/phpservice/json.php", 'POST', function(data) {
basicData = data.result;
console.log(basicData);
oTable = $("#table").dataTable({
bJQueryUI: true,
bPaginate: true,
sPaginationType: "full_numbers",
bFilter: false,
bInfo: false,
bProcessing: true,
bServerSide: true,
aaData: [basicData],
aoColumns: [{
"sTitle": "ANUMBER",
"mData": "aNumber"
}, {
"sTitle": "BNUMBER",
"mData": "bNumber"
}, {
"sTitle": "DATETIME",
"mData": "dateTime"
}, {
"sTitle": "DURATION",
"mData": "duration"
}, {
"sTitle": "IMEI",
"mData": "imei"
}]
});
}, function(error) {
console.log(error);
}, jsonStr);
}
By doing this, I am receiving 2 errors
DataTables warning: table id=table - Requested unknown parameter
'aNumber' for row 0, column 0. For more information about this error,
please see http://datatables.net/tn/4
and
Invalid JSON Response.
Is there any workaround for this type of problem, In which first, you will perform ajax call and from received data, you will populate datatable with server side processing ??
I hope someone will give me a hint at least.
With datatable 1.10,(i think you may be using an earlier version), you can populate and format the data in the cells, by using the columns.data property:
columns: [
{ data: "", defaultContent: " " },
{ data: null,
defaultContent: " ",
render: function (data, type, row, meta) {
return data.ID;
}
}
]
DataTable is showing but only after I change number of items per page. Similarly, pagination is only working if I search an item.
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var col = [{
"mData": "row1"
}, {
"mData": "row2"
}, {
"bSortable": false,
"mData": null,
"sTitle": "Actions",
"bSearchable": false,
"mRender": function(data, type, full) {
return '<img alt="Download" src="https://upload.wikimedia.org/wikipedia/commons/e/e3/Ppbc_icon_download.png" title="Download"/>';
}
}];
var ss = JSON.parse(xmlhttp.responseText);
$('#myTable').dataTable({
"aaData": ss,
"aoColumns": col,
"bDestroy": true
});
}
};
Instead of aoColumns, used columns.
var col = [{
"mData": "row1",
"sTitle": "row1"
}, // <-- which values to use inside object
{
"mData": "row2",
"sTitle": "row2"
}, {
"bSortable": false,
"mData": null,
"sTitle": "Download",
"bSearchable": false,
"mRender": function(data, type, full) {
return '<img alt="Download" src="https://upload.wikimedia.org/wikipedia/commons/e/e3/Ppbc_icon_download.png" title="Download"/>';
}
}];
JSON.parse(xmlhttp.responseText);
var ss = $('#myTable').dataTable({
"aaData": ss,
"columns": col,
"bDestroy": true
});
}
};
In the below code I have a jQuery DataTable and I want to get selected row ids and store it into array. But I get only one row id SchoolID but I want to get SchoolID, ClassID and SectionID for checked checkbox.
var val[]; //global
"aoColumns": [
{
"mDataProp": "SchoolID",
"bSearchable": false,
"bSortable": false,
"sWidth": "10%",
"mRender": function(data, type, full) {
val = '<input type="checkbox" id="chkSchoolID" onclick="CheckRow(' + full.SchoolID + ')"></button>';
return val;
}
},
{
"mDataProp": "SchoolID",
"sWidth": "25%"
}, {
"mDataProp": "ClassID",
"sWidth": "25%"
}, {
"mDataProp": "SectionID",
"sWidth": "25%"
},
],
function CheckRow() {
alert(val);
}
I want to create a datatable wherein my first column values come from an array and second and other columns contains custom html ( select boxes, inputs etc).I have used datatable before but that time i was reading data from json ( for all columns ) like this:
function basketTable(data){
topTable = $('#at-top-100').dataTable({
//layout of data table
"dom": 'Tlfrtip',
"bInfo" : false,
"bDestroy":true,
"bFilter" : false,
"responsive":true,
"aaData" : data,
"aoColumns": [
{ "mData": "Ap" },
{ "mData": "Dp" },
{ "mData": "A"},
{ "mData": "S"},
{ "mData": "S"},
],
"iDisplayLength": 10,
"oLanguage": {
"sSearch": "",
"sSearchPlaceholder" : "Search..",
"sLengthMenu": " _MENU_ ",
}
});
}
Any insight on how i can achieve this. Any help would be greatly appreciated!!
Use the "mrender" function and place any html you want to render per cell in the function.
You can also access the properties of the object in the row if you want to use them in your display.
http://legacy.datatables.net/usage/columns
function basketTable(data){
topTable = $('#at-top-100').dataTable({
//layout of data table
"dom": 'Tlfrtip',
"bInfo" : false,
"bDestroy":true,
"bFilter" : false,
"responsive":true,
"aaData" : data,
"aoColumns": [
{ "mData": "Ap" },
{ "mData": "Dp" },
{ "mData": "A"},
{ "mData": "S"},
{ "mData": "S",
"mRender": function(data,type,full)
{
return '<input type="text" value="Scanners and Scales"/>'
}
],
"iDisplayLength": 10,
"oLanguage": {
"sSearch": "",
"sSearchPlaceholder" : "Search..",
"sLengthMenu": " _MENU_ ",
}
});
}
Have a datatable and using the drill down row. The top row populate data but the link to drill down to the additional row contains a undefined object and I'm stuck right there.
Any help would be so appreciated. oData.code (undefinded) / oData itself will return everything from the linq query but when I start using the oData.etc... the object becomes undefined. Even in the click event I've tried to access oData and drop it in the second TD row and it to is also undefined.
function fnFormatDetails(oTable, nTr)
{
var oData = oTable.fnGetData(nTr);
var sOut =
'<div>' +
'<table>' +
'<tr><td> '+oData.code+' </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr>'
'</table>' +
'</div>';
return sOut;
} //end fnFormatDetails function
$(document).ready(function ()
{
var anOpen = [];
var oTable = $('#VADataTable').dataTable(
{
"sDom": 'T<"clear">lfrtip',
"oTableTools":
{
"sSwfPath": "/swf/copy_csv_xls_pdf.swf"
}, //flash must be enabled
"iDisplayLength": 5, //defalut amount of rows shown on page
"bServerSide": false, //uses sever for filter curently turned off
"bFilter": false, //makes columns clickable to filter
"bProcessing": true,
"bserverSide":false,
"bJQueryUI": true, //enables user interface
"bSort": true, //sorting for columns
"bScrollInfinite": true, //using this takes away ddl of selection
"sAjaxSource": "Data/IndustryTable", //where ajax commands renders results
"sScrollY": "200px",
"sScrollX": "100%",
"sScrollXInner": "100%",
"bScrollCollapse": true,
"fnRowCallback": function (nRow, aData)
{
if (aData[0] == "")
{
$('td:eq(0)', nRow).html("+").addClass('control');
}
return nRow;
}, //ends fnRowCallback
"aoColumns":
[
{ "sName": "code", "sTitle": "Code" },
{ "sName": "code" },
{ "sName": "data" },
{ "sName": "data" },
{ "sName": "data" },
{ "sName": "data" },
{ "sName": "data" }
]
});
$('#VADataTable td.control').live('click', function ()
{
var nTr = this.parentNode;
var i = $.inArray(nTr, anOpen);
if (i === -1)
{
$('td').attr('+');
var nDetailsRow = oTable.fnOpen(nTr, fnFormatDetails(oTable, nTr), 'details');
$('div', nDetailsRow).slideDown();
anOpen.push(nTr);
} //end if
else
{
$('td').attr('-');
$('div', $(nTr).next()[0]).slideUp(function ()
{
oTable.fnClose(nTr);
anOpen.splice(i, 1);
}); //ends slideUp
} //ends else
$('#new tr').after('<td> '+ typeof(oTable.code) +' </td>');
}); //ends click event
} //ends live event
)//ends ready function
I believe that just add the "mData" property in "aoColumns", that is the name of fields of database table, and in "fnRowCallback" you must replace "aData[0]" by "aData['code']" like the next example:
"fnRowCallback": function (nRow, aData)
{
if (aData['code'] == "")
{
$('td:eq(0)', nRow).html("+").addClass('control');
}
return nRow;
}, //ends fnRowCallback
"aoColumns":
[
{ "mData" : "code", "sName": "code", "sTitle": "Code" },
{ "mData" : "code", "sName": "code" },
{ "mData" : "data", "sName": "data" },
{ "mData" : "data", "sName": "data" },
{ "mData" : "data", "sName": "data" },
{ "mData" : "data", "sName": "data" },
{ "mData" : "data", "sName": "data" }
]