Tabulator total Rows count (Column Calculations) gets exported as well - tabulator

I am using this approach to show the total rows in a table:
var tabulator_table = new Tabulator("#example", {
columns: [
{ title: "name", field: "name", bottomCalc: "count", headerFilter: "input" },
{ title: "Type", field: "Type", bottomCalc: "count", headerFilter: "input" },
],
dataFiltered: function (filters, rows) {
var el = document.getElementById("search_count");
el.innerHTML = rows.length;
},
dataLoad: function (data) {
var el = document.getElementById("total_count");
el.innerHTML = data.length;
},
});
var total_count = $(".tabulator-footer").find('.tabulator-cell:first-child()').text();
$("#total_count").text(total_count);
$(".tabulator-footer").append("<span class='search_count' id='search_count'></span> Of<span class='search_result'>Total Productions: <span class='total_count'></span></span>")
var totalsearch = $("#total_count").text();
var resultsearch = $("#search_count").text();
$(".total_count").text(totalsearch)
$(".search_count").text(totalsearch);
//This CSS will hide the footer:
.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle {
display: none;
}
This works good but there is one issue: when i hit export to excel, it exports the calculation row as well such as:
Name Type
john human
1 1
How do I stop the count row (1 1) from being exported or is there other approach to show total rows.
This is the export function:
document.getElementById("myButtons").addEventListener("click", function () {
tabulator_table.download("xlsx", "name.xlsx", { sheetName: "Info" });
});

I think all you need is the downloadConfig option in your table options. http://tabulator.info/docs/4.6/download#advanced-config
So, just add downloadConfig: {columnCalcs: false} to your table options.
Here is a working example.
https://jsfiddle.net/nrayburn/0hn6v48r/11/

Related

Tabulator - Styling empty cells

I'm trying to style only tabulator empty cells.
I tried with a custom formatter but it seems to be called only on cells with data.
Any suggestion on how to proceed?
Seems to process fields without data just fine ...
https://jsfiddle.net/udpr2680/
new Tabulator("#tabulator", {
data:[{id:4957},{id:39857,price:100}],
columns: [
{ title: "number", field: "id"},
{ title: "price", field: "price",formatter: function(c,fP,onR) { let p = c.getData().price; if (p === undefined) return "undefined"; return p; } },
],
});

Tabulator calculating a total price

I've been going through Tabulator and so far think it's great in functionality and what it can achieve. However, I have been stuck for half a day trying to get some seemingly basic functionality working. It is to allow the user to input numerical values in a quantity field, and then it will calculate a total in a new column based on quantity * price.
I have looked and tried everything I can find online but it still does not work as intended. I feel it's mostly to my understanding of how mutators work. I did get one to work in a different page which statically calculated the values based on a stock value * price.
Here is what I have so far:
var totalEditor = function(cell, onRendered, success, cancel){
//cell - the cell component for the editable cell
//onRendered - function to call when the editor has been rendered
//success - function to call to pass the successfuly updated value to Tabulator
//cancel - function to call to abort the edit and return to a normal cell
var price = cell.getData().price;
var cellValue = cell.getValue(),
input = document.createElement("input");
input.setAttribute("type", "number");
input.value = cellValue;
onRendered(function()
{
input.focus();
input.style.height = "100%";
});
function onChange()
{
if(input.value >= 0)
{
success(cell.getRow().getData().quantity = input.value);
success(cell.getRow().getData().total = input.value * price);//Thought this would work
}
else
{
cancel();
}
}
//submit new value on blur or change
input.addEventListener("blur", onChange);
//submit new value on enter
input.addEventListener("keydown", function(e){
if(e.keyCode == 13){
onChange();
}
if(e.keyCode == 27){
cancel();
}
});
return input;
};
//custom mutator for static total calculation
var totalMutator = function(value, data, type, params, mutatorParams){
var qty = data.quantity;
var price = data.price;
return (Math.abs(qty) * Math.abs(price));
}
var table = new Tabulator("#example-table", {
//data:array2,
layout:"fitColumns",
placeholder:"No Data Set",
reactiveData: true,
columnCalcs:"both",
initialSort:[
{column:"name", dir:"asc"}, //sort by this first
],
columns:[
{title:"SKU", field:"sku", sorter:"string", width:100},
{title:"Name", field:"name", sorter:"string",headerFilter:"input"},
{title:"Price", field:"price", formatter: "money", formatterParams: { decimal: ".", thousand: ",", symbol: "$", precision: false,}, sorter:"number", width:100, align:"center"},
{title:"Quantity", width:100, field:"quantity", align:"center", editor:totalEditor, editorParams:{min:0,max:1000,step:1,}},
{title: "Total", width:100, field:"total", sorter:"number", align: "center", formatter: "money",formatterParams: { decimal: ".", thousand: ",", symbol: "$"}},
],
});
I also note that the input then does not not allow you to increment via the up and down arrows of the input box being number type.
Managed to get it working via updating the cell value through a cell edited function on the quantity cell. I also think that due to the total cell not being part of the data (a new cell created for the table) I needed to access it via getCell("total) rather than getData().total
var table = new Tabulator("#example-table", {
layout:"fitColumns",
placeholder:"No Data Set",
reactiveData: true,
columnCalcs:"both",
dataEdited:function(data){
},
initialSort:[{column:"name", dir:"asc"},],
columns:[
{title:"SKU", field:"sku", sorter:"string", width:100},
{title:"Name", field:"name", sorter:"string",headerFilter:"input"},
{title:"Price", field:"price", formatter: "money", formatterParams: { decimal: ".", thousand: ",", symbol: "$", precision: false,}, sorter:"number", width:100, align:"center"},
{title:"Quantity", width:100, field:"quantity", align:"center", editor: true,
cellEdited: function(cell) {
cell.getRow().getCell("total").setValue(cell.getRow().getData().price * cell.getValue());
}},
{title: "Total", width:100, field:"total", sorter:"number", align: "center", formatter: "money",formatterParams: { decimal: ".", thousand: ",", symbol: "$"}},
],
});

Uncaught TypeError: Cannot read property getColSpanningList

I am working with ag-Grid and Node.js to do some updates in the database. I am doing a calculation on 5 fields. I am using the onCellValueChanged event in order to do calculations for field2, field3, field4, field5 based of the change in field1. I can see the change when there is a mouse click event. However, the problem arises when I hit the TAB key on the keyboard. It gives me this error:
ag-grid-community.min.noStyle.js:110 Uncaught TypeError: Cannot read property 'getColSpanningList' of undefined
at t.getLastCellOfColSpan (ag-grid-community.min.noStyle.js:110)
at t.findNextCellToFocusOn (ag-grid-community.min.noStyle.js:110)
at t.moveToNextEditingCell (ag-grid-community.min.noStyle.js:110)
at t.moveToCellAfter (ag-grid-community.min.noStyle.js:110)
at t.onTabKeyDown (ag-grid-community.min.noStyle.js:110)
at t.onTabKeyDown (ag-grid-community.min.noStyle.js:242)
at t.onKeyDown (ag-grid-community.min.noStyle.js:242)
at t.processKeyboardEvent (ag-grid-community.min.noStyle.js:530)
This is my ejs template:
selection.ejs
var tableCols = <%- JSON.stringify(tables) %>;
var rowData = tableCols;
var columnDefs = [
{headerName: "Field1", field: "field1", editable: true},
{headerName: "Field2", field: "field2"},
{headerName: "Field3", field: "field3"},
{headerName: "Field4", field: "field4"},
{headerName: "Field5", field: "field5"},
{headerName: "Total", field: "total"}
];
var gridOptions = {
columnDefs: columnDefs,
rowData: rowData,
onCellValueChanged: function(params){
var d = params.data.field1;
var id = params.data.Unique_ID;
params.field2 = (.25 * params.data.field1).toFixed(2);
var q = params.data.field2;
params.data.field3 = (0 * params.data.field1).toFixed(2);
var b = params.data.field3;
params.data.field4 = (.175 * params.data.field1).toFixed(2);
var p = params.data.field4;
params.data.field5 = (.20 * params.data.field1).toFixed(2);
var a = params.data.field5;
params.data.total = (parseFloat(params.data.field1) + parseFloat(params.field2 ) + parseFloat(params.data.field3) + parseFloat(params.data.field4) + parseFloat(params.data.field5)).toFixed(0);
var t = params.data.total;
this.api.refreshCells();
},
onCellEditingStarted: function(event){
console.log("started");
},
// this is where the error happens, then logs "cellEditingStopped"
onCellEditingStopped: function(event) {
console.log('cellEditingStopped');
}
};
I don't understand how can pressing the TAB key cause the error, but not on MOUSE click. Any help would be appreciated. Thank you.
I can reproduce this issue. When you tab to the next column with editable: false, it will give the error. If you comment the option editable: false, tab will work without the problem.
I guess you may need to implement your own tabToNextCell: https://www.ag-grid.com/javascript-grid-keyboard-navigation/#tabtonextcell
I am figuring out how to skip the editable: false cell.

Counting number of rows matching criteria between two dates

I am trying to query a postgres db table for a count of rows matching some criteria between a time range. I am using the sequelize orm with nodejs.
In my controller method i have a query
var query = 'SELECT o.ordered_at, COUNT(o.id) AS order_count FROM "Orders" o WHERE status = :status AND o.ordered_at >= :lower_limit AND o.ordered_at <= :upper_limit GROUP BY o.id ORDER BY o.ordered_at DESC';
models.sequelize.query(query, queryOptions).
then(function (orders) {
res.status(200).json(response);
}).
catch(function (err) {
logger.error(err);
res.status(500).json(err.message);
})
this yields a response like this
[
{
"ordered_at": "2016-12-10T16:05:46.525Z",
"order_count": "1"
},
{
"ordered_at": "2016-12-10T16:03:46.429Z",
"order_count": "1"
},
{
"ordered_at": "2016-12-10T16:01:46.440Z",
"order_count": "1"
},
{
"ordered_at": "2016-12-05T12:20:18.714Z",
"order_count": "1"
},
{
"ordered_at": "2016-12-05T12:18:18.650Z",
"order_count": "1"
},
{
"ordered_at": "2016-12-03T12:16:18.658Z",
"order_count": "1"
}
]
You can see the query returns the order_count for each row instead of for each order, so i am try to transform the data here
var data = [],
lower_time_limit = t(new Date());
var range = _.range(30),
month_lower_limit = t(lower_time_limit).subtract(1, 'M').startOf('day');
var lower_limit,
limit,
upper_limit;
_.forEach(range, function (day, key) {
limit = t(month_lower_limit);
lower_limit = t(limit.add(day, 'd'));
upper_limit = t(limit.add(1, 'd'));
_.forEach(orders, function (order, index) {
var count = 0;
if (t(order.ordered_at).isBetween(lower_limit, upper_limit, 'second', '[)')) {
var orderCount = count + parseInt(order.order_count);
data.push({date: lower_limit, count: orderCount})
}
});
});
return data;
I know am missing something, just can't figure it out.
GROUP BY o.id will produce one group (i.e. one row in the output) per o.id. You want one group for all matching rows, which is what you get if you omit the GROUP BY entirely.
Including o.ordered_at in your output doesn't make a whole lot of sense; if you're aggregating multiple matching rows into a single output record, it's not clear whose ordered_at time you'd be expecting to see.
And once you've got one row of output, an ORDER BY won't do you much good.
With all of that in mind:
SELECT COUNT(o.id) AS order_count
FROM "Orders" o
WHERE status = :status
AND o.ordered_at >= :lower_limit
AND o.ordered_at <= :upper_limit

YUI-grid: re load data

Hi guys
I am try to research Yahoo lib- grid. I created a button to display grid. But when i click button N times -> it is displayed N grids. I only want display one grid and after click button it will get data from server again. My code like below:
Please help me., Thank you.
YUI({ filter: 'raw' }).use("jsonp", "node",function (Y) {
function handleJSONP(response) {
// Y.one("#out").setContent(Y.Lang.sub(template, response.user));
YUI().use("datatable-base", function(Y) {
var cols = [
{ key: "id", label: "Transaction No", abbr: "id"},
{ key: "userName", label: "User Name", abbr: "userName"},
{ key: "storeName", label: "StoreName", abbr: "storeName"}
],
data = response.Root,
dt = new Y.DataTable.Base({
columnset: cols,
recordset: data,
summary: "Price sheet for inventory parts",
caption: "These columns have labels and abbrs"
}).render("#example");
});
}
Y.one("#demo_btn").on("click", function (e) {
var url = "server.jsp"+ "?callback={callback}";
Y.jsonp(url, handleJSONP);
});
});
You should be using the DataSource utility to retrieve the data via JSONP. This will allow you to then reload the data via something like
dt.datasource.load();
See the docs for details: DataTable + DataSource.Get + JSON Data
Your handler needs to check if you've already created the table.
var dt;
if (dt === null) {
dt = new Y.DataTable.Base // etc.
}

Resources