I m using DataTable (Jquery) to export excel file. But I facing on how do put extra information to export excel file. I have tried some code but it didn't meet my expectation.
My expected exported excel file is as below picture:
However my output is as below picture, my title report and address is located at middle isn't on top of report:
with using code below:
{
extend: 'excelHtml5',
title: 'Trace Report',
messageTop: 'ABC company' + 'address',
//message: "Any message for header inside the file. I am not able to put message in next row in excel file but you can use \n"+'modelID'+modelId,
render: function (data, type, full, meta) {
return 'Download'; //change the button text here
},
customize: function (xlsx) {
var sheet = xlsx.xl.worksheets['sheet1.xml'];
var numrows = 10;
// add styles for the column header, these row will be moved down
var clRow = $('row', sheet);
//$(clRow[0]).find('c').attr('s', 32);
//update Row
clRow.each(function () {
var attr = $(this).attr('r');
var ind = parseInt(attr);
ind = ind + numrows;
//ind is num of row +1
$(this).attr("r", ind);
});
// Create row before data
$('row c ', sheet).each(function (index) {
var attr = $(this).attr('r');
var pre = attr.substring(0, 1);
//pre=A,B,C..-F repeat 5 time
var ind = parseInt(attr.substring(1, attr.length));
ind = ind + numrows;
$(this).attr("r", pre + ind);
});
function addRow(index, data) {
var row = sheet.createElement('row');
row.setAttribute("r", index);
for (i = 0; i < data.length; i++) {
var key = data[i].k;
var value = data[i].v;
var c = sheet.createElement('c');
c.setAttribute("t", "inlineStr");
c.setAttribute("s", "2"); /*set specific cell style here*/
c.setAttribute("r", key + index);
var is = sheet.createElement('is');
var t = sheet.createElement('t');
var text = sheet.createTextNode(value)
t.appendChild(text);
is.appendChild(t);
c.appendChild(is);
row.appendChild(c);
debugger;
}
return row;
}
//add data to extra rows
var countryStateList = 'asd';
var agencyValue = 'asd';
var reportGroupList = 'asd';
var certNo = '3e'
var r1 = addRow(1, [{
k: 'A',
v: 'Certificate Number'
}, {
k: 'B',
v: 'Model ID:'
}, {
k: 'C',
v: 'Serial Number'
}, {
k: 'D',
v: 'Calibration Date'
}]);
var r2 = addRow(2, [{
k: 'A',
v: countryStateList
}, {
k: 'B',
v: agencyValue
}, {
k: 'C',
v: reportGroupList
}, {
k: 'D',
v: certNo
}]); //add one cell for row 1
//$('row c[r^="A"]', sheet).attr( 's', '25' );
var sheetData = sheet.getElementsByTagName('sheetData')[0];
// sheetData.insertBefore(r4,sheetData.childNodes[0]);
// sheetData.insertBefore(r3,sheetData.childNodes[0]);
sheetData.insertBefore(r2, sheetData.childNodes[0]);
sheetData.insertBefore(r1, sheetData.childNodes[0]);
}
}
Related
I am trying to export DataTable into excel file (.xlsx).
In jQuery, I am removing the unwanted rows.
When I try to open the excel file, it is showing:
"Excel found unreadable content in '[filename].xlsx'. Do you want to recover the contents of this workbook? If you trust the source of this workbook, click Yes."
The error is showing as:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<recoveryLog
xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<logFileName>error128600_02.xml</logFileName><summary>Errors were detected
in file '[filename].xlsx'</summary><removedRecords summary="Following is a
list of removed records:"><removedRecord>Removed Records: Cell information
from /xl/worksheets/sheet1.xml part</removedRecord></removedRecords>
</recoveryLog>
The exported file is opening fine in OpenOffice with removed rows.
Here is the code to remove unwanted rows:
I have 5 Columns in my DataTable and removing the unwanted rows based on columns 3,4,5
customize: function (xlsx) {
var exportData=[];
var sheet =xlsx.xl.worksheets['sheet1.xml'];
var clR = $('row', sheet);
var clR = $('row', sheet);
$('row', sheet).filter(function () {
var attr = $(this).attr('r');
if(attr>3)
{
if($(this).context.children.length===5){
var Item1= parseInt($(this).context.children[2].children[0].textContent);
var Item2= parseInt($(this).context.children[3].children[0].textContent);
var Item3= parseInt($(this).context.children[4].children[0].textContent);
if(Item1===0 && Item2 ===0 && Item3===0 ){
return true;
}
else{
exportData.push([{ key: 'A', value: $(this).context.children[0].children[0].textContent },
{ key: 'B', value: $(this).context.children[1].children[0].textContent },
{ key: 'C', value: $(this).context.children[2].children[0].textContent },
{ key: 'D', value: $(this).context.children[3].children[0].textContent },
{ key: 'E', value: $(this).context.children[4].children[0].textContent }]);
}
return false;
}
}
}).remove();
//update Row
clR.each(function () {`enter code here`
var attr = $(this).attr('r');
var ind = parseInt(attr);
if(ind>3){
$(this).remove();
}
});
// Create row before data
$('row c ', sheet).each(function () {
var attr = $(this).attr('r');
var pre = attr.substring(0, 1);
if(pre>3){
$(this).remove();
}
});
function Addrow(index,data) {
msg='<row r="'+index+'">'
for(i=0;i<data.length;i++){
var key=data[i].key;
var value=data[i].value;
msg += '<c t="inlineStr" r="' + key + index + '">';
msg += '<is>';
msg += '<t>'+value+'</t>';
msg+= '</is>';
msg+='</c>';
}
msg += '</row>';
return msg;
}
//insert
var addrows="";
exportData.each(function (item,index) {
var r1 = Addrow(index+4, item);
addrows=r1+addrows;
});
sheet.childNodes[0].childNodes[1].innerHTML = sheet.childNodes[0].childNodes[1].innerHTML+addrows;
}
I currently have a solution using AngularJS/SpreadJS where we need to update the header section with a formula. When we change a cell value in the header using setValue everythign displays ok, however we need to display a formula using setFormula, in these cases the formula gets calculated and displayed in the rows belonging to the actual sheet where my data is at.
//Does not work and displays in row 2 of the sheet:
sheet.setFormula(2, i, formula, GC.Spread.Sheets.SheetArea.colHeader);
//Displays value in actual header in teh correct location/header cell
sheet.setValue(2, i, 'my formula!', GC.Spread.Sheets.SheetArea.colHeader);
Any help will be appreciated. Thanks!
Implemented below solution to achieve the SUM formula in Column Header of the spread sheet.This function can be called on spread sheet events like cellChanged,clipBoardPasted to achieve functionality.
var spread = new GC.Spread.Sheets.Workbook($("#ss").get(0), { sheetCount: 2 });
var displaySheet = spread.getSheet(0);
displaySheet.setRowCount(2, GC.Spread.Sheets.SheetArea.colHeader);
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
displaySheet.setValue(i, j, i + j);
}
}
$("#btnSetAutoTotal").click(function () {
setTotal(displaySheet, 0);
});
function setTotal(sheet, columnIndex) {
var formula = "SUM(R[1]C[1]:R[10]C[10]";
value = GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, 'SUM(A:A)', 0,
columnIndex, false);
sheet.setValue(0, columnIndex, value, GC.Spread.Sheets.SheetArea.colHeader);
};
The team created this sample to demonstrate what you need. Hope this helps.
function setColumnHeaderFunction() {
this.name = "SetColumnHeader";
this.maxArgs = 3;
this.minArgs = 3;
}
setColumnHeaderFunction.prototype = new GC.Spread.CalcEngine.Functions.Function();
setColumnHeaderFunction.prototype.description = function () {
return {
name:"SetColumnHeader",
description: "The function will apply the calc result on specified column",
parameters: [{
name: "result",
description: "The value which will be setted on column"
}, {
name: "rowIndex",
description: "The row index"
}, {
name: "colIndex",
description: "The column index"
}]
}
}
setColumnHeaderFunction.prototype.evaluate = function () {
var value = arguments[0], rowIndex = arguments[1], colIndex = arguments[2];
var spread = GC.Spread.Sheets.findControl("ss");
var sheet = spread.getSheet(0);
sheet.setValue(rowIndex, colIndex, value, GC.Spread.Sheets.SheetArea.colHeader);
}
$(document).ready(function () {
var spread = new GC.Spread.Sheets.Workbook($("#ss").get(0), {sheetCount: 2});
spread.addCustomFunction(new setColumnHeaderFunction());
var displaySheet = spread.getSheet(0);
displaySheet.setDataSource(getSource(100));
displaySheet.setRowCount(3, GC.Spread.Sheets.SheetArea.colHeader);
displaySheet.setValue(0,0,"Count:",GC.Spread.Sheets.SheetArea.colHeader);
displaySheet.setValue(0,3,"Sum:",GC.Spread.Sheets.SheetArea.colHeader);
displaySheet.setValue(0,4,"Average:",GC.Spread.Sheets.SheetArea.colHeader);
displaySheet.setValue(0,5,"Sum:",GC.Spread.Sheets.SheetArea.colHeader);
var calcSheet = spread.getSheet(1);
calcSheet.visible(false);
calcSheet.setFormula(0, 1, "SetColumnHeader(SUM(Sheet1!D:D),1,3)");
calcSheet.setFormula(0, 2, "SetColumnHeader(AVERAGE(Sheet1!E:E),1,4)");
calcSheet.setFormula(0, 3, "SetColumnHeader(SUM(Sheet1!F:F),1,5)");
calcSheet.setFormula(0, 4, "SetColumnHeader(COUNT(Sheet1!A:A),1,0)");
});
function getSource(count) {
var dataList = [];
var _lines = ["Computers", "Washers", "Stoves"];
var _colors = ["Red", "Green", "Blue", "White"];
for (var i = 0; i < count; i++) {
dataList.push({
id: i,
line: _lines[parseInt(Math.random() * 3)],
color: _colors[parseInt(Math.random() * 4)],
price: parseInt(Math.random() * 501 + 500),
cost: parseInt(Math.random() * 601),
weight: parseInt(Math.random() * 101),
})
}
return dataList;
}
function listFiles() {
var x = document.getElementById("ResultShown").value;
var date = new Date();
date.setDate(date.getDate() - 180);
var n = date.toISOString().split('.')[0] ;
var test = false;
gapi.client.drive.files.list({
pageSize: x,
q: "starred = "+test+" and viewedByMeTime < '"+n+"'",
orderBy: 'quotaBytesUsed desc',
fields: "nextPageToken, files(id, name, viewedByMeTime, mimeType, quotaBytesUsed, webViewLink)",
}
).then(function(response) {
var table = document.getElementById('content');
appendPre('Files:');
appendRow(table, ['Name', 'Last Viewed', 'Link', 'Size'], 'th');
var files = response.result.files;
var table = document.getElementById('content');
if (files && files.length > 0) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
appendRow(table, [
file.name +" ",
file.viewedByMeTime.split('.')[0]+" ",
link(file.webViewLink),
file.quotaBytesUsed + ' bytes'
])
}
} else {
appendPre('No files found.');
}
});
}
Currently, every time I click a button to activate this function, a new list comes up, what can I add to it that will make the button clear the old list before putting a new one out?
Edit #1:
In this screenshot, you can see that every time I press a button to call on list file function, a new list comes up, instead of having a million list, I want it so everytime I clear the button, it clears the old list and replaces it with a new list
I only want one thing showing at a time.
You can remove all but the header row in your table element before adding new rows to it:
var table = document.getElementById('content');
var rows = table.rows;
while (rows.length > 1) rows[1].parentNode.removeChild(rows[1]);
Full Updated Code
appendPre('Files:');
appendRow(table, ['Name', 'Last Viewed', 'Link', 'Size'], 'th');
function listFiles() {
var x = document.getElementById("ResultShown").value;
var date = new Date();
date.setDate(date.getDate() - 180);
var n = date.toISOString().split('.')[0];
var test = false;
gapi.client.drive.files.list({
pageSize: x,
q: "starred = " + test + " and viewedByMeTime < '" + n + "'",
orderBy: 'quotaBytesUsed desc',
fields: "nextPageToken, files(id, name, viewedByMeTime, mimeType, quotaBytesUsed, webViewLink)",
}
).then(function(response) {
var table = document.getElementById('content');
var files = response.result.files;
var table = document.getElementById('content');
var rows = table.rows;
while (rows.length > 1) rows[1].parentNode.removeChild(rows[1]);
if (files && files.length > 0) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
appendRow(table, [
file.name + " ",
file.viewedByMeTime.split('.')[0] + " ",
link(file.webViewLink),
file.quotaBytesUsed + ' bytes'
])
}
} else {
appendPre('No files found.');
}
});
}
Note: This answer may seem out of context, because it builds on my answers to additional questions OP has asked concerning the same project.
I based my logic on the code suggested here http://jsfiddle.net/LkLkd405/4/
I added 2 new items to the default context menu (code from my helpers module)
addColHideItemsToContextMenu: function(hot, colsToHide, globalColumns, globalHeaders){
var items = hot.contextMenu.defaultOptions.items;
//console.log("items: "+JSON.stringify(items));
//hide_col based on existing remove_col
var hideColItem = {
key: 'hide_col',
name: 'Hide column',
callback: function(key, selection) {
//remove_col code
//var amount = selection.end.col - selection.start.col + 1;
//this.alter("remove_col", selection.start.col, amount);
//hide_col custom code
colsToHide.push(selection.start.col);
var newCols = [];
var newHeaders = [];
for (var i = 0; i < globalHeaders.length; i++) {
if (colsToHide.indexOf(i) === -1) {
newCols.push(globalColumns[i]);
newHeaders.push(globalHeaders[i]);
}
}
hot.updateSettings({
columns: newCols,
colHeaders: newHeaders
});
},
disabled: function() {
var selected = this.getSelected(),
entireRowSelection = [selected[0], 0, selected[0], this.countCols() - 1],
rowSelected = entireRowSelection.join(',') == selected.join(',');
return (selected[1] < 0 || rowSelected);
}
};
items.push(hideColItem);
var showAllColItem = {
key: 'showall_cols',
name: 'Show all columns',
callback: function(key, selection) {
//var amount = selection.end.col - selection.start.col + 1;
//this.alter("remove_col", selection.start.col, amount);
colsToHide = [];
hot.updateSettings({
columns: globalColumns,
colHeaders: globalHeaders
});
},
disabled: function() {
return false;
}
};
items.push(showAllColItem);
},
I then have a server side paging module can receives json objects from the server and converts them to an array of arrays, else new columns cannot be added.
EnhancementPager: function(paramObj) {
var handsontableIntegration = function(rows){// called line 283
paramObj.handsonDataObjects = rows;//received from the server and not used again
paramObj.handsonDataArrays = help.buildArrayFromObjs(rows);
paramObj.globalHeaders = help.extractColHeaders(rows[0]);
paramObj.globalColumns = help.buildArrayDataSourceColumnConfig(paramObj.handsonDataArrays[0]);
paramObj.colsToHide = [];
if(paramObj.table){
var hot = paramObj.table;
hot.updateSettings({
colHeaders: paramObj.globalHeaders,
columns: paramObj.globalColumns
});
help.addColHideItemsToContextMenu(hot, paramObj.colsToHide, paramObj.globalColumns, paramObj.globalHeaders);
hot.loadData(paramObj.handsonDataArrays);
}
}
This is what the grid looks like on load - notice the values on the top row
This is what the top row changes to after hiding the column
Then is I select the show all context item
The top row changes to this
I've only been working with handsontable for a few days, it's a really well written and organised js api. But I'm pretty mystified by this behaviour.
Hello I am trying to append a custom type of cell I created to my backgrid instance but I keep getting the following error:
Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
I Console.logged the collection and the columns it turns out the above exception occurs on my custom cell. I think it is because it does not have a column attribute:
This is what my custom cell looks like:
return QuestionCell.extend({
distractors: ['-', 't', 'f'],
template: 'gradescreen/table/mc',
render: function () {
var $val_td, view = this, correct_td = '',
current_state = view.model.get('responses').stateModel.get('state'),
correct_answer = '', selected = '-', select = '', pos, key_length;
view.current_response = view.getCurrentResponse(view.model);
if (view.current_response.get('response').prefix) {
selected = view.current_response.get(
'response'
).prefix === 'a' ? 't':'f';
}
if (view.question_meta.get('correct_prefix') ===
view.current_response.get(
'response').prefix) {
correct_td = ' correct_td';
}
$val_td = $('<td class="response_td' + correct_td + '" />');
app.fetchTemplate(view.template, function (tmpl) {
$val_td.html(tmpl({cid: view.cid, q_number: view.question_number}));
key_length = _.keys(view.question_meta.get('answers')).length;
for (pos = 0; pos <= key_length; pos++) {
var prefix = view.distractors[pos];
correct_answer =
prefix === view.question_meta.get('correct_prefix') ?
'correct_response':'';
select = selected === prefix ? 'selected="true"':'';
$('#answer_options_' + view.cid, $val_td).append(
'<option class="' + correct_answer + '" ' + select + ' >' +
prefix + '</option>');
}
if (current_state > 2) {
$('#answer_options_' + view.cid, $val_td).prop('disabled', true);
}
//view.bindEvents($val_td);
});
this.el = $val_td;
return this;
}
});
});
It is extended from a cell I call as a QuestionCell which is extended from Backgrid.Cell and only contains from default attributes and methods.
This is how I am passing the cell to backgrid.
var grid, columns = [];
_.each(questions, function (question, position) {
if (question.get('type') === 'tf')
{
columns.push({
name: 'responses[0]',
label: 'Q-' + (position + 1),
cell: TFCell.extend({
question_meta : question,
question_number: position + 1,
group_id: view.group_id
})
});
}
else
{
//this last one isn't getting rendered for some reason.
columns.push({
label: 'Q-' + (position + 1),
cell: Backgrid.SelectCell.extend({
optionValues: [
['-', '-'], ['a', 'a'], ['b', 'b'],
['c', 'c'], ['d', 'd']
]
})
});
}
});
grid = new Backgrid.Grid({
columns: columns,
collection: view.model.get('student_responses')
});
$('#Student_Grid').append(grid.render().$el);
Please help. How can I get this to get rendered. Many Thanks
Reading through the documentation it looks like it's supposed to be
$('#Student_Grid').append(grid.render().el);
instead of
$('#Student_Grid').append(grid.render().$el);
$el looks like a function where as el is the node object that you'd want to append.