Datatables: Export Excel Formatting - javascript

I'm having some issues when trying to format data when exporting to Excel using datatables. One of my columns contain a decimal point and displays OK when viewed in the browser as a table. When I export the table to excel this is rounding up the number in that column, this I do not want to happen. e.g shown in table '220419.07109' and when exported '220419.0711' I would prefer if this was just a string to maintain the full number.
function formatDataForExport(data, row, column, node) {
var string = data.toString();
return string;
}
function drawDatatable(JSONData) {
var dataSet = [];
table = $("#div").DataTable({
data: dataSet,
columns: columns(),
columnDefs: [{
"targets": columnTargets(showConcludedColumns),
"visible": false,
"searchable": false
}],
info: false,
searching: false,
paging: false,
ordering: false,
autoWidth: true,
responsive: true,
buttons: [{
extend: 'excel',
text: "Export to Excel",
exportOptions: {
columns: ":visible",
format: {
body: formatDataForExport
}
}
}]
});
}

You could use the following solution.
// Get the max value of an attribute of elements' list
var getMaxValue = function(elements, attr) {
var values = elements.map(function(){
return this.getAttribute(attr) || -Infinity;
}).toArray();
return Math.max.apply(Math, values);
}
$('#example').DataTable( {
dom: 'Bfrtip',
columns: [
{ data: 'Number' },
],
buttons: [
{
extend: 'excelHtml5',
customize: function(xlsx) {
//Get the built-in styles
//refer buttons.html5.js "xl/styles.xml" for the XML structure
var styles = xlsx.xl['styles.xml'];
//Create a custom number format
//Get the available id for the custom number format
var numFmtId = getMaxValue($('numFmts numFmt', styles), 'numFmtId') + 1
//XML Node: Custom number format for the timestamp column
var nFmt = '<numFmt numFmtId="' + numFmtId + '" formatCode="0.######################"/>';
// Add new node
el = $('numFmts', styles);
el.append(nFmt).attr('count', parseInt(el.attr('count'))+1);
//Create our own style to use the custom number format above
//XML Node: Custom style for the timestamp column
var style = '<xf numFmtId="' + numFmtId + '" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>';
// Add new node
el = $('cellXfs', styles);
el.append(style).attr('count', parseInt(el.attr('count'))+1);
// Index of our new style
var styleIdx = $('xf', el).length - 1;
//Apply new style to the first (A) column
var sheet = xlsx.xl.worksheets['sheet1.xml'];
//Set new style default for the column (optional)
$('col:eq(0)', sheet).attr('style', styleIdx);
//Apply new style to the existing rows of the first column ('A'), skipping header row
$('row:gt(0) c[r^="A"]', sheet).attr('s', styleIdx);
},
},
]
} );
Working JSFiddle
You could use different kinds of formatting there:
0.###################### - will show as many digits after decimal point as you have "#";
#.###################### - the same as above, but with no 0 in a number like 0.1234;
0.?????????????????????? - the same as above, but aligned by the decimal point
Simplified version, the resulted file opens correctly in Excel, but the shortcuts could affect other XLSX files reading software: JSFiddle

Related

How to use tabulator list editor together with html formatter?

I have options defined by id, label, description, e.g.
id
label
description
1
foo
foo_description
2
baa
baa_description
And would like to use them in a tabulator column.
The label should be used for display
The description should be shown as hover title of the label.
The id should be used when getting data from the table with getData()
I tried to use a list editor in combination with a html cell formatter for a column.
It kind of works. If I hover over a cell in the table, I can see a hover title. And hover titles
are shown for the options in the list/select editor, too.
However, when opening the list editor, the currently selected value is not shown as html foo any more but as text <span title=...>foo.
After closing the editor, the cell is shown correctly again.
=> How can I format the currently selected value of the list editor?
=> Or how should I otherwise define a tabular column to fulfills my needs?
I also tried to use an item formatter for the list editor to show html titles. That works inside the list editor but the table cell does not show a tool tip.
I could solve it with a combination of
custom cell formatter for the table
custom item formatter for the list editor
custom object class used for the values
converting columns that include custom value objects to ids before returning the data
class SelectableValue {
constructor(id, label, description){
this._id = id;
this._label = label;
this._description = description;
}
toString(){
return '<span title="'+ this._description +'">' + this._label + '<span>';
}
get id(){
return this.id;
}
}
_createDefaultColumns(endUseItems){
let endUseColumn = {
title: "End Use",
field: "id_end_use",
editor: "list",
formatter: this._cellFormatter,
editorParams: {
values: endUseItems,
itemFormatter: this._optionFormatter,
valueToIdConverter: this._valueToIdConverter
}
};
const columns = [
endUseColumn,
{ title: 2020, field: "2020", editor: true },
{ title: 2025, field: "2025", editor: true },
{ title: 2030, field: "2030", editor: true },
];
return columns;
}
_valueToIdConverter(selectableValue){
//defines what data is returned from the table as
//replacement for the stored object / displayed label
return selectableValue.id;
}
_cellFormatter(cell, formatterParams, onRendered){
//defines how table cells are shown
let selectableValue = cell.getValue();
return selectableValue.toString();
}
_optionFormatter(label, selectableValue, item, element){
//defines how options of the cell editor are shown
return selectableValue.toString();
}
_endUseItems(){
let items = []
let endUseRows = this._context.endUses.rows
for (let row of endUseRows){
let id = row[0];
let label = row[1];
let description = row[2];
let value = new SelectableValue(id, label, description)
let item = {
'value': value, //Value stored in table; includes unique id
'label': label //Used as label for the currently selected item
//when cell editor is openend
}
items.push(item);
}
return items;
}
_convertValues(displayData, columns){
let data = structuredClone(displayData);
for (let column of columns){
let _valueToIdConverter = this._valueToIdConverter(column);
if(_valueToIdConverter){
let field = column.field;
for(let row of data){
let value = row[field];
let id = _valueToIdConverter(value);
row[field] = id;
}
}
}
return data;
}

Access specific line Datatable

I am defining a Datatable this way:
var dat_one = $('#dat_one').DataTable({
select: {
style: 'single'
},
responsive: true,
});
I would like to access a specific line of my datatable. I want to color a line that contains a specific string. (Example: Line that contains 'Ashton Cox' as column 1 and 'San Francisco' as column 3
I tried to color a selected line with this code :
$(".selected").css('background-color', '#ccffcc');
But doesn't works if my line is not selected.
Try using rowCallback. There you can change row attributes with value checking.
$('#example').dataTable( {
"rowCallback": function( row, data ) {
if ( data.grade == "A" ) {
$('td:eq(4)', row).html( '<b>A</b>' );
}
}
} );
This is documentation. Note the function has many other parameters you can use.
rowCallback( row, data, displayNum, displayIndex, dataIndex )
Following documentation, this is an alternative to Aruna Perera:
// var table = $('#dat_one').DataTable() ;
dat_one.rows().eq(0).each( function ( index ) {
var row = table.row( index );
var data = row.data();
var column0value = data[0];
if(column0value == "Airi Satou"){
$(row.node()).css("background-color", "yellow")
}
// ... do something with data(), or row.node(), etc
} );

jexcel table SUM column after change

I want to sum a column in jexcel after entering a value
This code is not working I don't know why:
var change = function(instance, cell, value) {
var cellName = $(instance).jexcel('getColumnNameFromId',$(cell).prop('id'));
$('#log').append('New change on cell'+ cellName+'to:'+ value + '<br>');
var thisid = $(cell).prop('id');
var splitted = thisid.split("-");
var nextcellid = ++splitted[1];
var nextcell = '0-'+nextcellid;
console.log(nextcell,'nextcell');
$("td#"+nextcell).html('<span>total</span>');
}
using onafterchange event:
$('#my').jexcel({
data:data,
colHeaders: ['Model'],
colWidths: [ 300 ],
onafterchange:function(instance){
console.log(instance)
},
columns: [
{ type: 'text' },
]
});
full handing events ready this url
https://bossanova.uk/jexcel/docs/events
or using this example
https://bossanova.uk/jexcel/examples/including-formulas-on-your-spreadsheet
To be honest, you can just use =SUM(A1:A10) in the column you would like to have the total. Pretty much like excel.

SyntaxError: missing ) after formal parameters when adding if/else

Can anyone tell me what i am doing wrong , i want to have different views for different users in handsontable.I am defining the table as
document.addEventListener("DOMContentLoaded", function() {
var create_table = document.getElementById('create_table');
var mydata = document.getElementById('mydata').innerHTML;//to get the hidden element
var logged_user = document.getElementById('logged_user').innerHTML;// to get remote user
var plan_creator = document.getElementById('plan_creator').innerHTML;//to get the person who has created the plan
console.log(logged_user + " " + plan_creator);
console.log(mydata);
var searchResultCount=0;
var hot,searchFiled,resultCount;
function searchResultCounter(instance, row, col, value, result) {
Handsontable.plugins.Search.DEFAULT_CALLBACK.apply(this, arguments);
if (result) {
searchResultCount++;
}
}
var buttons = {
save:document.getElementById('save'),
load:document.getElementById('load'),
file:document.getElementById('file_export')
}
var objectData = JSON.parse(mydata);//to decode data in JSON format
console.log(objectData);
hot = new Handsontable(create_table, {
data:objectData,
colHeaders: true,
rowHeaders: true,
contextMenu: true,
minRows: 30,
minCols: 13,
maxCols:18,
maxRows:100,
copyPaste:true,
dropdownMenu: true,//plugin to display menu on column header
filters:true,
columnSorting:true,//plugin to enable sorting
sortIndicator:true,//to display sorting is done
comments:true,//to add comments
colHeaders:["Testcase Name","Cell Name","Customer","Flops","Title","Status","Mfix CCR","Scenerio Brief Description","Expected Results","CCR Status","CCR No","Remarks","Testcase Path"],
if(logged_user == plan_creator) {
columns:[//when using this not able to remove column
{data:'tc_name'},
{data:'cell_name'},
{data:'customer_name'},
{data:'flops' ,type:'numeric'},
{data:'title'},
{data:'status'},
{data:'mfix_ccr'},
{data:'test_scenerio'},
{data:'expected_results'},
{data:'ccr_status'},
{data:'ccr_num'},
{data:'remarks'},
{data:'tc_path'}],
}
else{
columns:[//when using this not able to remove column
{data:'tc_name' ,readOnly:true } ,
{data:'cell_name',readOnly:true },
{data:'customer_name',readOnly:true },
{data:'flops' ,type:'numeric',readOnly:true },
{data:'title',readOnly:true },
{data:'status',readOnly:true },
{data:'mfix_ccr',readOnly:true },
{data:'test_scenerio',readOnly:true },
{data:'expected_results',readOnly:true },
{data:'ccr_status',readOnly:true },
{data:'ccr_num',readOnly:true },
{data:'remarks'},//only remarks can be added by other user
{data:'tc_path',readOnly:true }],
}
search: {
callbak:searchResultCounter
}
});
searchFiled = document.getElementById('search_filed');
resultCount=document.getElementById('resultCount');
var exportPlugin=hot.getPlugin('exportFile');
Handsontable.dom.addEvent(searchFiled, 'keyup', function(event) {
var queryResult;
console.log(this.value);
searchResultCount = 0;
queryResult = hot.search.query(this.value);
console.log(queryResult);
//resultCount.innerText = searchResultCount.toString();
hot.render();
});
buttons.file.addEventListener('click', function() {// enabling the plugin to download the file
exportPlugin.downloadFile('csv', {filename: 'MyFile',columnHeaders:true});
});
I don't get any error when i remove the if/else statement and use only one scenerio .when using above code i am getting the error, but when i remove the if/else part and just use columns attribute in a simple way , i don't get this error.But i want to have different views for the creator of plan and others.
Is there any other way to do this?
Thanks
You can't use if statements when constructing an object, but you can use the ternary ?: operator, like this:
colHeaders: ... ,
columns: logged_user == plan_creator
? /* value in case they are equal */
: /* value in case they are not equal */,
search: ...
instead of using if else like
if(logged_user == plan_creator) {
columns:[//when using this not able to remove column
{data:'tc_name'},
{data:'cell_name'},
{data:'customer_name'},
{data:'flops' ,type:'numeric'},
{data:'title'},
{data:'status'},
{data:'mfix_ccr'},
{data:'test_scenerio'},
{data:'expected_results'},
{data:'ccr_status'},
{data:'ccr_num'},
{data:'remarks'},
{data:'tc_path'}],
}
else {}
you could use the ternary Operator:
columns: (logged_user === plan_creator)
? [//when using this not able to remove column
{data:'tc_name'},
...
]
: [//when using this not able to remove column
{data:'tc_name' ,readOnly:true },
...
]

Refreshing gridx cell value using DateTextBox

Working with gridx. I've added a Diji/form/DateTextBox to one of the columns.
I am able to save back to the grid's JSON, but I am not managing to update what is displayed in the cell.
function deadlineDecorator(value) {
return '<div data-dojo-type="dijit/form/DateTextBox" data-dojo-props="constraints:{datePattern: \'dd/MM/yyyy\'}" data-dojo-attach-point="deadlineCal" required="true" />';
}
function <portlet:namespace/>deadlineCellValueSet(gridData, storeData, cellWidget) {
cellWidget.deadlineCal.set('value', newDate(gridData));
cellWidget.deadlineCal.constraints.min = new Date();
}
var locale = dojo.require("dojo.date.locale");
function getDate(d){
res = locale.format(d, {
selector: 'date',
datePattern: 'dd/MM/yyyy'
});
return res;
}
function deadlineChange(cellWidget, cell) {
return [
[cellWidget.deadlineCal, 'onChange', function(e){
cell.setRawData(getDate(cellWidget.deadlineCal.value));
}]
];
}
I am creating the grid using this:
data = [{"id": 1, "dead": 18/12/2014}];
function creategrid() {
var gridData = {data: data};
var dataStore = new dojo.store.Memory(gridData);
grid.setStore(datastore);
};
How can I save the chosen date back to the JSON AND show that change in the cell.
I guess I could refresh the whole grid, but that doesn't seem like a very elegant solution?

Categories

Resources