Reputation: 901
I have a table which behaves correctly until I use the Category Picker.
Correct Behavior:
Problematic Behavior: I would like to be able to select a row and receive a result without having to sort the gender column first.
How can I get success without having to sort a column first?
Grazie mille!
google.charts.load('current', {
'packages': ['corechart', 'table', 'gauge', 'controls', 'charteditor']
});
$(document).ready(function () {
//console.log("ready!");
renderChart_onPageLoad();
});
function renderChart_onPageLoad() {
google.charts.setOnLoadCallback(function () {
//console.log("renderChart_onPageLoad");
drawDashboard();
});
}
function drawDashboard() {
//console.log("drawDashboard");
var data = google.visualization.arrayToDataTable([
['Name', 'RoolNumber', 'Gender', 'Age', 'DonutsEaten'],
['Michael', 1, 'Male', 12, 5],
['Elisa', 2, 'Female', 20, 7],
['Robert', 3, 'Male', 7, 3],
['John', 4, 'Male', 54, 2],
['Jessica', 5, 'Female', 22, 6],
['Aaron', 6, 'Male', 3, 1],
['Margareth', 7, 'Female', 42, 8],
['Miranda', 8, 'Female', 33, 6]
]);
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard'));
var categoryPicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'categoryPicker',
options: {
filterColumnLabel: 'Gender',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: false
}
}
});
var proxyTable = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'div_proxyTable',
options: {
width: '500px'
}
});
var table = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'div_table',
options: {
sort: 'event', // <-- set sort to 'event' for table totaling
width: '500px',
allowHtml: true,
page: 'enable',
pageSize: '5',
}
});
//This json contains my settings for later
let json = {
"tableChart": {
"hasTable": true,
"dataView": {
"columns": [
{ "id": "Name" },
{ "id": "RoolNumber" },
{ "id": "Gender" },
{ "id": "Age" },
{ "id": "DonutsEaten" }
]
},
"groupView": {
"hasGroupView": false
},
"totalRow": {
"hasTotalRow": true,
"labelCol": "Total",
"labelColIndex": 0,//This is the column where the words "Grand Total" are stored. It must be text column.
"totalColumns": [
{ "id": "RoolNumber", "type": "number", "function": "sum" }
]
},
"conditionalFormat": {
"hasConditionalFormat": false
},
"options": {},
"hasCSV": false,
"clickGetFunc": null
},
};
google.visualization.events.addOneTimeListener(proxyTable, 'ready', function () {
console.log(".addOneTimeListener(proxyTable, 'ready' - sort");
google.visualization.events.addOneTimeListener(table, 'ready', function () {
console.log(".addOneTimeListener(table, 'ready' - sort");
//#region table - sort: 'event'
google.visualization.events.addListener(table.getChart(), 'sort', function (sender) {
console.log(".addListener(table.getChart(), 'sort' - sorted");
//// update table --> options must include (sort: 'event') for total row to work properly
//// update var grandTotal = tableData.getFilteredRows([{column: 0,
//// update .draw() 'table' references to new name if using for a different table variable
// sort data table according to sort properties
var tableData = table.getDataTable();
var sortIndexes = tableData.getSortedRows({
column: sender.column,
desc: !sender.ascending
});
//#region reposition total row - if required
let totalRow = (json.tableChart.totalRow !== undefined) ? json.tableChart.totalRow : [];
let hasTotalRow = totalRow.hasTotalRow;
if (hasTotalRow) {
// find grand total row
var grandTotal = tableData.getFilteredRows([{
column: json.tableChart.totalRow.labelColIndex, //must be placed in a column which is of type string.
value: json.tableChart.totalRow.labelCol
}]);
if (grandTotal.length > 0) {
// find grand total in sort
var grandTotalSort = sortIndexes.indexOf(grandTotal[0]);
// remove grand total from sort
sortIndexes.splice(grandTotalSort, 1);
// add grand total as first index
sortIndexes.unshift(grandTotal[0]);
}
}
//#endregion
// set table sort arrow
table.setOption('sortAscending', sender.ascending);
table.setOption('sortColumn', sender.column);
// set table view & re-draw table
table.setView({ rows: sortIndexes });
table.draw();
//Table ready then fires
});
//#endregion
});
});
google.visualization.events.addOneTimeListener(proxyTable, 'ready', function () {
console.log(".addOneTimeListener(proxyTable, 'ready' - select");
google.visualization.events.addOneTimeListener(table, 'ready', function () {
console.log(".addOneTimeListener(table, 'ready' - select");
test_gcharts_selectedRowCol(table, json.tableChart.clickGetFunc);//(wrapperName, callback)
});
});
google.visualization.events.addListener(proxyTable, 'ready', function () {
console.log(".addListener(proxyTable, 'ready' - redrawTable()");
redrawTable(json.tableChart);
});
dashboard.bind([categoryPicker], [proxyTable]);
dashboard.draw(data);
//This is a table builder which uses json from above. This is working ok. Contains no listeners.
function redrawTable(tableChart) {
console.log('redrawTable()');
// set defaults for any undefined settings
let dataView = (tableChart.dataView !== undefined) ? tableChart.dataView : [];
let groupView = (tableChart.groupView !== undefined) ? tableChart.groupView : [];
let totalRow = (tableChart.totalRow !== undefined) ? tableChart.totalRow : [];
let conditionalFormat = (tableChart.conditionalFormat !== undefined) ? tableChart.conditionalFormat : [];
// update .draw() 'table' or 'chart' references when using a different or additional chart name
var sourceData = proxyTable.getDataTable().toDataTable().clone();
//console.log('sourceData', sourceData);
//#region create data view - this is used as basis for dataResults
let view = new google.visualization.DataView(sourceData);
//#region create group view - if required
let dataResults_forTable;
let hasGroupView = groupView.hasGroupView;
if (hasGroupView) {
// create keys for grouping
const groupKeys = [];
for (let i = 0; i < groupView.keys.length; i++) {
groupKeys.push(
groupKey_default(view, groupView.keys[i]),
);
};
// create columns for aggregating
const groupColumns = [];
for (let i = 0; i < groupView.columns.length; i++) {
groupColumns.push(
groupColumn_default(view, groupView.columns[i]),
);
};
// create data aggregation
let group = google.visualization.data.group(view, groupKeys, groupColumns);
//console.log('group'); console.log(group);
dataResults_forTable = group.clone();
}
else {
dataResults_forTable = view.toDataTable().clone();
}//END if (hasGroupView) {
//console.log('dataResults_forTable', dataResults_forTable);
//#endregion
//#region create total row - if required
let hasTotalRow = totalRow.hasTotalRow;
if (hasTotalRow) {
let labelCol = totalRow.labelCol;
let labelColIndex = totalRow.labelColIndex;
let totalColumns = totalRow.totalColumns;
//Create groupColumns for total row aggregation calculations
const groupColumns = [];
for (let i = 0; i < totalColumns.length; i++) {
const column = { column: dataResults_forTable.getColumnIndex(totalColumns[i].id), type: 'number' }
switch (totalColumns[i].function) {
case 'sum': column.aggregation = google.visualization.data.sum; break;
case 'count': column.aggregation = google.visualization.data.count; break;
case 'average': column.aggregation = google.visualization.data.avg; break;
case 'min': column.aggregation = google.visualization.data.min; break;
case 'max': column.aggregation = google.visualization.data.avg; break;
default: column.aggregation = google.visualization.data.sum;
}
groupColumns.push(column);
}
let groupTotal = google.visualization.data.group(dataResults_forTable,
// need key column to group on, so we want all rows grouped into 1, then it needs a constant value
[{ column: 0, type: "number", modifier: function () { return 1; } }], groupColumns);
// this code block will run if the filter results in rows available to total. Otherwise the table will present no rows.
if (groupTotal.getNumberOfRows() !== 0) {
let formatDecimal = new google.visualization.NumberFormat({ pattern: '#,###.##' });
for (let i = 1; i < groupTotal.getNumberOfColumns(); i++) { formatDecimal.format(groupTotal, i); }
// create Grand Total row from colToTotal and groupTotal
const gtRow = [];
for (let i = 0; i < dataResults_forTable.getNumberOfColumns(); i++) {
//Build GT Row to match length of dataResults_forTable
gtRow.push(null);
}
//Push words "Grand Total" into it's set position in gtRow - It must go into a column of type string.
gtRow[labelColIndex] = labelCol;
for (let i = 0; i < totalColumns.length; i++) {
//Loop through groupColumns, test setting type for string.
if (totalColumns[i].type === 'string') {
//Convert to number from groupTotal result to string to match the column it's being pushed into
gtRow[dataResults_forTable.getColumnIndex(totalColumns[i].id)] = String(groupTotal.getValue(0, i + 1));
}
else {
//Otherwise push in the number value
gtRow[dataResults_forTable.getColumnIndex(totalColumns[i].id)] = groupTotal.getValue(0, i + 1);
}
}
//console.log('insertRow', insertRow);
// insert complete gtRow with values into row position 0
dataResults_forTable.insertRows(0, [gtRow]);
// add formatting for grand total row to highlight && justify to right if of type number
for (let j = 0; j < dataResults_forTable.getNumberOfColumns(); j++) {
//if statement on column type for left right justification
if (dataResults_forTable.getColumnType(j) === 'number') {
dataResults_forTable.setColumnProperty(j, 'className', 'googleTableTextRight');
dataResults_forTable.setProperty(0, j, 'className', 'googleTableTotalRow googleTableTextRight');//stored in css file
} else {
dataResults_forTable.setProperty(0, j, 'className', 'googleTableTotalRow');//stored in css file
}
}
//console.log('dataResults_forTable', dataResults_forTable);
}//END (groupTotal.getNumberOfRows() !== 0) {
}//END if (hasTotalRow) {
//#endregion
//#region conditional formatting - if required
let hasConditionalFormat = conditionalFormat.hasConditionalFormat;
if (hasConditionalFormat) {
dataResults_forTable = conditionalFormatting_default(dataResults_forTable, conditionalFormat);
}//END if (hasConditionalFormat) {
//#endregion
var finalView_forTable = new google.visualization.DataView(dataResults_forTable);
//console.log('finalView_forTable', finalView_forTable);
// set reset sorting, set dataTable & draw chart
table.setView(null); // reset in case sorting has been used via user click
table.setDataTable(finalView_forTable);//includes any total row
table.draw();
}//END redrawChart()
}
function test_gcharts_selectedRowCol(wrapperName, callback) {
//console.log('wrapperName', wrapperName); console.log('callback', callback)
//NEW - Works with paging active
// initialize page number and size
var page = 0;
var pageSize = 10;
if (wrapperName.getOption('page') === 'enable') {
page = wrapperName.getOption('startPage');
pageSize = wrapperName.getOption('pageSize');
}
test_enableCoordinates(callback);
// page event
google.visualization.events.addListener(wrapperName.getChart(), 'page', function (sender) {
console.log(".addListener(wrapperName.getChart(), 'page' - paged - test_enableCoordinates called");
page = sender.page; // save current page
test_enableCoordinates(callback);
});
// sort event
google.visualization.events.addListener(wrapperName.getChart(), 'sort', function () {
console.log(".addListener(wrapperName.getChart(), 'sort' - sorted - test_enableCoordinates called ")
page = 0; // reset back to first page
test_enableCoordinates(callback);
});
function test_enableCoordinates(callback) {
//console.log('callback enableCoordinates', callback);
//remove event listeners
var container = document.getElementById(wrapperName.getContainerId());
Array.prototype.forEach.call(container.getElementsByTagName('td'), function (cell) {
cell.removeEventListener("click", test_selectCell, false);
});
//add event listeners
var container = document.getElementById(wrapperName.getContainerId());
Array.prototype.forEach.call(container.getElementsByTagName('td'), function (cell) {
cell.addEventListener('click', test_selectCell, false);
});
}
function test_selectCell(sender) {
var cell = sender.target;
var row = cell.closest('tr');
var wrapperDataTable = wrapperName.getDataTable();
var selectedRow = row.rowIndex - 1; // adjust for header row (-1)
selectedRow = (page * pageSize) + selectedRow; // adjust for page number
// Original from whitehat - save sorted info
// This version does not work after a user clicks a column to sort
//var sortInfo = wrapperName.getChart().getSortInfo();
//if (sortInfo.sortedIndexes !== null) {
// selectedRow = sortInfo.sortedIndexes[selectedRow];
//}
// Replaced code to which finds the view row order by .getView then taking the selected row
// and returning the number which is in the .getView result
var sortInfo = wrapperName.getView(); // save sorted info
if (sortInfo !== null) {
selectedRow = sortInfo.rows[selectedRow];
}
var selectedCol = cell.cellIndex;
//var result = "selectedRow: " + selectedRow + " selectedCol: " + selectedCol;
//var ul = document.getElementById("demo");
//var li = document.createElement("li");
//li.innerHTML = result;
//ul.appendChild(li);
var selectedValue = wrapperDataTable.getValue(selectedRow, selectedCol);
var colID = wrapperDataTable.getColumnId(selectedCol);
var colLabel = wrapperDataTable.getColumnLabel(selectedCol);
var result = //removed array brackets
{
"selectedRow": selectedRow,
"selectedCol": selectedCol,
"selectedValue": selectedValue,
"colID": colID,
"colLabel": colLabel
};
//callback(result, wrapperDataTable);
console.log('test_selectCell', result);
return result;
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<div id="dashboard">
<div id="categoryPicker"></div><br />
Proxy Table<br />
<div id="div_proxyTable" style="display:none;"></div><br />
Table<br />
<div id="div_table"></div><br /><br />
</div>
================MULTIPLE DASHBOARDS SCENARIO=====================
The solution provided works for a single drawDashboard() scenerio. However it breaks down in a multiple drawDashboard() scenerio which I would like to discuss next.
I will be adding additional drawDashboard()
functions to this page.
They also require the same functionality and remain independent from each other.
Is there a way to accommodate multiple drawDashboard()
function without global variables?
Do I move listenerPage
and listenerSort
inside a specific drawDashboard()
function to self contain?
I wish to maintain only one library function test_gcharts_selectedRowCol()
and not duplicate it for a additional drawDashboard()
additions?
https://jsfiddle.net/cmill/pvj23nfk/
On run, drawDashboard_A()
begins with listenerPage
and listenerSort
= null. It will then execute the .addListener
routine for each.
Then as drawDashboard_B()
runs listenerPage
and listenerSort
are no longer null but have been set by the pass made by drawDashboard_A()
.
The sorting and click events work perfectly and as needed and return results.
Bad Behavior:
Click page 2 in drawDashboard_A()
Click a row - FAIL - no result.
click page 2 in drawDashboard_B()
click a row - PASS - receive a result.
Upvotes: 2
Views: 785
Reputation: 61230
to correct the issue with the table cell select event,
use addListener
instead of addOneTimeListener
, here...
google.visualization.events.addOneTimeListener(proxyTable, 'ready', function () {
console.log(".addOneTimeListener(proxyTable, 'ready' - select");
// USE addListener HERE
google.visualization.events.addListener(table, 'ready', function () {
console.log(".addOneTimeListener(table, 'ready' - select");
test_gcharts_selectedRowCol(table, json.tableChart.clickGetFunc);//(wrapperName, callback)
});
});
then to ensure we don't get multiple sort and page events,
save a reference to the listener handles when adding,
and remove before adding again.
we can use an object to store the handlers,
and the container id of the chart wrapper as the key...
// save handles to event listeners
var listenerPage = {};
var listenerSort = {};
function test_gcharts_selectedRowCol(wrapperName, callback) {
//console.log('wrapperName', wrapperName); console.log('callback', callback)
//NEW - Works with paging active
// initialize page number and size
var page = 0;
var pageSize = 10;
if (wrapperName.getOption('page') === 'enable') {
page = wrapperName.getOption('startPage');
pageSize = wrapperName.getOption('pageSize');
}
test_enableCoordinates(callback);
// remove previous event handlers
if (listenerPage.hasOwnProperty(wrapperName.getContainerId())) {
google.visualization.events.removeListener(listenerPage[wrapperName.getContainerId()]);
delete listenerPage[wrapperName.getContainerId()];
}
if (listenerSort.hasOwnProperty(wrapperName.getContainerId())) {
google.visualization.events.removeListener(listenerSort[wrapperName.getContainerId()]);
delete listenerSort[wrapperName.getContainerId()];
}
// page event
listenerPage[wrapperName.getContainerId()] = google.visualization.events.addListener(wrapperName.getChart(), 'page', function(sender) {
console.log(".addListener(wrapperName.getChart(), 'page' - paged - test_enableCoordinates called");
page = sender.page; // save current page
test_enableCoordinates(callback);
});
// sort event
listenerSort[wrapperName.getContainerId()] = google.visualization.events.addListener(wrapperName.getChart(), 'sort', function() {
console.log(".addListener(wrapperName.getChart(), 'sort' - sorted - test_enableCoordinates called ")
page = 0; // reset back to first page
test_enableCoordinates(callback);
});
see following working snippet...
google.charts.load('current', {
'packages': ['corechart', 'table', 'gauge', 'controls', 'charteditor']
}).then(drawDashboard);
function drawDashboard() {
//console.log("drawDashboard");
var data = google.visualization.arrayToDataTable([
['Name', 'RoolNumber', 'Gender', 'Age', 'DonutsEaten'],
['Michael', 1, 'Male', 12, 5],
['Elisa', 2, 'Female', 20, 7],
['Robert', 3, 'Male', 7, 3],
['John', 4, 'Male', 54, 2],
['Jessica', 5, 'Female', 22, 6],
['Aaron', 6, 'Male', 3, 1],
['Margareth', 7, 'Female', 42, 8],
['Miranda', 8, 'Female', 33, 6]
]);
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard'));
var categoryPicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'categoryPicker',
options: {
filterColumnLabel: 'Gender',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: false
}
}
});
var proxyTable = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'div_proxyTable',
options: {
width: '500px'
}
});
var table = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'div_table',
options: {
sort: 'event', // <-- set sort to 'event' for table totaling
width: '500px',
allowHtml: true,
page: 'enable',
pageSize: '5',
}
});
//This json contains my settings for later
let json = {
"tableChart": {
"hasTable": true,
"dataView": {
"columns": [{
"id": "Name"
},
{
"id": "RoolNumber"
},
{
"id": "Gender"
},
{
"id": "Age"
},
{
"id": "DonutsEaten"
}
]
},
"groupView": {
"hasGroupView": false
},
"totalRow": {
"hasTotalRow": true,
"labelCol": "Total",
"labelColIndex": 0, //This is the column where the words "Grand Total" are stored. It must be text column.
"totalColumns": [{
"id": "RoolNumber",
"type": "number",
"function": "sum"
}]
},
"conditionalFormat": {
"hasConditionalFormat": false
},
"options": {},
"hasCSV": false,
"clickGetFunc": null
},
};
google.visualization.events.addOneTimeListener(proxyTable, 'ready', function() {
console.log(".addOneTimeListener(proxyTable, 'ready' - sort");
google.visualization.events.addOneTimeListener(table, 'ready', function() {
console.log(".addOneTimeListener(table, 'ready' - sort");
//#region table - sort: 'event'
google.visualization.events.addListener(table.getChart(), 'sort', function(sender) {
console.log(".addListener(table.getChart(), 'sort' - sorted");
//// update table --> options must include (sort: 'event') for total row to work properly
//// update var grandTotal = tableData.getFilteredRows([{column: 0,
//// update .draw() 'table' references to new name if using for a different table variable
// sort data table according to sort properties
var tableData = table.getDataTable();
var sortIndexes = tableData.getSortedRows({
column: sender.column,
desc: !sender.ascending
});
//#region reposition total row - if required
let totalRow = (json.tableChart.totalRow !== undefined) ? json.tableChart.totalRow : [];
let hasTotalRow = totalRow.hasTotalRow;
if (hasTotalRow) {
// find grand total row
var grandTotal = tableData.getFilteredRows([{
column: json.tableChart.totalRow.labelColIndex, //must be placed in a column which is of type string.
value: json.tableChart.totalRow.labelCol
}]);
if (grandTotal.length > 0) {
// find grand total in sort
var grandTotalSort = sortIndexes.indexOf(grandTotal[0]);
// remove grand total from sort
sortIndexes.splice(grandTotalSort, 1);
// add grand total as first index
sortIndexes.unshift(grandTotal[0]);
}
}
//#endregion
// set table sort arrow
table.setOption('sortAscending', sender.ascending);
table.setOption('sortColumn', sender.column);
// set table view & re-draw table
table.setView({
rows: sortIndexes
});
table.draw();
//Table ready then fires
});
//#endregion
});
});
google.visualization.events.addOneTimeListener(proxyTable, 'ready', function() {
console.log(".addOneTimeListener(proxyTable, 'ready' - select");
google.visualization.events.addListener(table, 'ready', function() {
console.log(".addOneTimeListener(table, 'ready' - select");
test_gcharts_selectedRowCol(table, json.tableChart.clickGetFunc); //(wrapperName, callback)
});
});
google.visualization.events.addListener(proxyTable, 'ready', function() {
console.log(".addListener(proxyTable, 'ready' - redrawTable()");
redrawTable(json.tableChart);
});
dashboard.bind([categoryPicker], [proxyTable]);
dashboard.draw(data);
//This is a table builder which uses json from above. This is working ok. Contains no listeners.
function redrawTable(tableChart) {
console.log('redrawTable()');
// set defaults for any undefined settings
let dataView = (tableChart.dataView !== undefined) ? tableChart.dataView : [];
let groupView = (tableChart.groupView !== undefined) ? tableChart.groupView : [];
let totalRow = (tableChart.totalRow !== undefined) ? tableChart.totalRow : [];
let conditionalFormat = (tableChart.conditionalFormat !== undefined) ? tableChart.conditionalFormat : [];
// update .draw() 'table' or 'chart' references when using a different or additional chart name
var sourceData = proxyTable.getDataTable().toDataTable().clone();
//console.log('sourceData', sourceData);
//#region create data view - this is used as basis for dataResults
let view = new google.visualization.DataView(sourceData);
//#region create group view - if required
let dataResults_forTable;
let hasGroupView = groupView.hasGroupView;
if (hasGroupView) {
// create keys for grouping
const groupKeys = [];
for (let i = 0; i < groupView.keys.length; i++) {
groupKeys.push(
groupKey_default(view, groupView.keys[i]),
);
};
// create columns for aggregating
const groupColumns = [];
for (let i = 0; i < groupView.columns.length; i++) {
groupColumns.push(
groupColumn_default(view, groupView.columns[i]),
);
};
// create data aggregation
let group = google.visualization.data.group(view, groupKeys, groupColumns);
//console.log('group'); console.log(group);
dataResults_forTable = group.clone();
} else {
dataResults_forTable = view.toDataTable().clone();
} //END if (hasGroupView) {
//console.log('dataResults_forTable', dataResults_forTable);
//#endregion
//#region create total row - if required
let hasTotalRow = totalRow.hasTotalRow;
if (hasTotalRow) {
let labelCol = totalRow.labelCol;
let labelColIndex = totalRow.labelColIndex;
let totalColumns = totalRow.totalColumns;
//Create groupColumns for total row aggregation calculations
const groupColumns = [];
for (let i = 0; i < totalColumns.length; i++) {
const column = {
column: dataResults_forTable.getColumnIndex(totalColumns[i].id),
type: 'number'
}
switch (totalColumns[i].function) {
case 'sum':
column.aggregation = google.visualization.data.sum;
break;
case 'count':
column.aggregation = google.visualization.data.count;
break;
case 'average':
column.aggregation = google.visualization.data.avg;
break;
case 'min':
column.aggregation = google.visualization.data.min;
break;
case 'max':
column.aggregation = google.visualization.data.avg;
break;
default:
column.aggregation = google.visualization.data.sum;
}
groupColumns.push(column);
}
let groupTotal = google.visualization.data.group(dataResults_forTable,
// need key column to group on, so we want all rows grouped into 1, then it needs a constant value
[{
column: 0,
type: "number",
modifier: function() {
return 1;
}
}], groupColumns);
// this code block will run if the filter results in rows available to total. Otherwise the table will present no rows.
if (groupTotal.getNumberOfRows() !== 0) {
let formatDecimal = new google.visualization.NumberFormat({
pattern: '#,###.##'
});
for (let i = 1; i < groupTotal.getNumberOfColumns(); i++) {
formatDecimal.format(groupTotal, i);
}
// create Grand Total row from colToTotal and groupTotal
const gtRow = [];
for (let i = 0; i < dataResults_forTable.getNumberOfColumns(); i++) {
//Build GT Row to match length of dataResults_forTable
gtRow.push(null);
}
//Push words "Grand Total" into it's set position in gtRow - It must go into a column of type string.
gtRow[labelColIndex] = labelCol;
for (let i = 0; i < totalColumns.length; i++) {
//Loop through groupColumns, test setting type for string.
if (totalColumns[i].type === 'string') {
//Convert to number from groupTotal result to string to match the column it's being pushed into
gtRow[dataResults_forTable.getColumnIndex(totalColumns[i].id)] = String(groupTotal.getValue(0, i + 1));
} else {
//Otherwise push in the number value
gtRow[dataResults_forTable.getColumnIndex(totalColumns[i].id)] = groupTotal.getValue(0, i + 1);
}
}
//console.log('insertRow', insertRow);
// insert complete gtRow with values into row position 0
dataResults_forTable.insertRows(0, [gtRow]);
// add formatting for grand total row to highlight && justify to right if of type number
for (let j = 0; j < dataResults_forTable.getNumberOfColumns(); j++) {
//if statement on column type for left right justification
if (dataResults_forTable.getColumnType(j) === 'number') {
dataResults_forTable.setColumnProperty(j, 'className', 'googleTableTextRight');
dataResults_forTable.setProperty(0, j, 'className', 'googleTableTotalRow googleTableTextRight'); //stored in css file
} else {
dataResults_forTable.setProperty(0, j, 'className', 'googleTableTotalRow'); //stored in css file
}
}
//console.log('dataResults_forTable', dataResults_forTable);
} //END (groupTotal.getNumberOfRows() !== 0) {
} //END if (hasTotalRow) {
//#endregion
//#region conditional formatting - if required
let hasConditionalFormat = conditionalFormat.hasConditionalFormat;
if (hasConditionalFormat) {
dataResults_forTable = conditionalFormatting_default(dataResults_forTable, conditionalFormat);
} //END if (hasConditionalFormat) {
//#endregion
var finalView_forTable = new google.visualization.DataView(dataResults_forTable);
//console.log('finalView_forTable', finalView_forTable);
// set reset sorting, set dataTable & draw chart
table.setView(null); // reset in case sorting has been used via user click
table.setDataTable(finalView_forTable); //includes any total row
table.draw();
} //END redrawChart()
}
// save handles to event listeners
var listenerPage = {};
var listenerSort = {};
function test_gcharts_selectedRowCol(wrapperName, callback) {
//console.log('wrapperName', wrapperName); console.log('callback', callback)
//NEW - Works with paging active
// initialize page number and size
var page = 0;
var pageSize = 10;
if (wrapperName.getOption('page') === 'enable') {
page = wrapperName.getOption('startPage');
pageSize = wrapperName.getOption('pageSize');
}
test_enableCoordinates(callback);
// remove previous event handlers
if (listenerPage.hasOwnProperty(wrapperName.getContainerId())) {
google.visualization.events.removeListener(listenerPage[wrapperName.getContainerId()]);
delete listenerPage[wrapperName.getContainerId()];
}
if (listenerSort.hasOwnProperty(wrapperName.getContainerId())) {
google.visualization.events.removeListener(listenerSort[wrapperName.getContainerId()]);
delete listenerSort[wrapperName.getContainerId()];
}
// page event
listenerPage[wrapperName.getContainerId()] = google.visualization.events.addListener(wrapperName.getChart(), 'page', function(sender) {
console.log(".addListener(wrapperName.getChart(), 'page' - paged - test_enableCoordinates called");
page = sender.page; // save current page
test_enableCoordinates(callback);
});
// sort event
listenerSort[wrapperName.getContainerId()] = google.visualization.events.addListener(wrapperName.getChart(), 'sort', function() {
console.log(".addListener(wrapperName.getChart(), 'sort' - sorted - test_enableCoordinates called ")
page = 0; // reset back to first page
test_enableCoordinates(callback);
});
function test_enableCoordinates(callback) {
//console.log('callback enableCoordinates', callback);
//remove event listeners
var container = document.getElementById(wrapperName.getContainerId());
Array.prototype.forEach.call(container.getElementsByTagName('td'), function(cell) {
cell.removeEventListener("click", test_selectCell, false);
});
//add event listeners
var container = document.getElementById(wrapperName.getContainerId());
Array.prototype.forEach.call(container.getElementsByTagName('td'), function(cell) {
cell.addEventListener('click', test_selectCell, false);
});
}
function test_selectCell(sender) {
var cell = sender.target;
var row = cell.closest('tr');
var wrapperDataTable = wrapperName.getDataTable();
var selectedRow = row.rowIndex - 1; // adjust for header row (-1)
selectedRow = (page * pageSize) + selectedRow; // adjust for page number
// Original from whitehat - save sorted info
// This version does not work after a user clicks a column to sort
//var sortInfo = wrapperName.getChart().getSortInfo();
//if (sortInfo.sortedIndexes !== null) {
// selectedRow = sortInfo.sortedIndexes[selectedRow];
//}
// Replaced code to which finds the view row order by .getView then taking the selected row
// and returning the number which is in the .getView result
var sortInfo = wrapperName.getView(); // save sorted info
if (sortInfo !== null) {
selectedRow = sortInfo.rows[selectedRow];
}
var selectedCol = cell.cellIndex;
//var result = "selectedRow: " + selectedRow + " selectedCol: " + selectedCol;
//var ul = document.getElementById("demo");
//var li = document.createElement("li");
//li.innerHTML = result;
//ul.appendChild(li);
var selectedValue = wrapperDataTable.getValue(selectedRow, selectedCol);
var colID = wrapperDataTable.getColumnId(selectedCol);
var colLabel = wrapperDataTable.getColumnLabel(selectedCol);
var result = //removed array brackets
{
"selectedRow": selectedRow,
"selectedCol": selectedCol,
"selectedValue": selectedValue,
"colID": colID,
"colLabel": colLabel
};
//callback(result, wrapperDataTable);
console.log('test_selectCell', result);
return result;
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<div id="dashboard">
<div id="categoryPicker"></div><br />
Proxy Table<br />
<div id="div_proxyTable" style="display:none;"></div><br />
Table<br />
<div id="div_table"></div><br /><br />
</div>
Upvotes: 1