Reputation: 253
So I have been experimenting with Google Apps Script and the Charts API all day, and have gotten nowhere, unfortunately.
I did many things - including following Mogsdad's well-written tutorial here. Here's the code I have so far - including from that tutorial, but I keep getting an error saying the script has completed but returned a different type from what is accepted, or something of the like.
Dashboard-Code.gs:
/**
* Serves HTML of the application for HTTP GET requests.
* From gist.github.com/mogsdad/24518dff348ad14d3929
*
* @param {Object} e event parameter that can contain information
* about any URL parameters provided.
*/
function doGet(e) {
var template = HtmlService.createTemplateFromFile('Index');
// Build and return HTML in IFRAME sandbox mode.
return template.evaluate()
.setTitle('Dashboard demo')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
/**
* Return all data from first spreadsheet as an array. Can be used
* via google.script.run to get data without requiring publication
* of spreadsheet.
* From gist.github.com/mogsdad/24518dff348ad14d3929
*
* Returns null if spreadsheet does not contain more than one row.
*/
function getSpreadsheetData() {
// This does not work, see https://code.google.com/p/google-apps-script-issues/issues/detail?id=5233
// var ss = SpreadsheetApp.getActiveSpreadsheet();
// var data = ss.getSheets()[0].getDataRange().getValues();
var sheetId = '1-EE_WDD6QYi257_utUf_D0v5e9Gf8Lj5tETPqqllvxk'; // Replace with your spreadsheet ID. (Ick.)
var data = SpreadsheetApp.openById(sheetId).getSheets()[0].getDataRange().getValues();
return (data.length > 1) ? data : null;
}
Index.html:
<!-- Use a templated HTML printing scriptlet to import common
stylesheet. -->
<?!= HtmlService.createHtmlOutputFromFile('Stylesheet').getContent(); ?>
<html>
<body>
<h1 id="main-heading">Loading...</h1>
<div id="dashboard-div">
<div id="control-div">
<div id="selector-div">
</div>
<div id="selector1-div">
</div>
</div>
<div id="charts-div">
<div id="table-div">
</div>
</div>
</div>
<div class="hidden" id="error-message">
</div>
</body>
</html>
<!-- Store data passed to template here, so it is available to the
imported JavaScript. -->
<script>
</script>
<!-- Use a templated HTML printing scriptlet to import JavaScript. -->
<?!= HtmlService.createHtmlOutputFromFile('JavaScript').getContent(); ?>
and JavaScript.html (I decided to stick to what Mogsdad was saying):
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('45', {packages: ['corechart']});
google.charts.setOnLoadCallback(drawChart);
</script>
<script>
// Load the Visualization API and desired package(s).
google.load('visualization', '1.0', {'packages':['controls']});
/**
* Run initializations on dialog load.
*/
$(function() {
// Set a callback to run when the Google Visualization API is loaded.
// Note: could also be accomplished via google.load options.
google.setOnLoadCallback(sendQuery);
// Assign handler functions to dialog elements here, if needed.
// Call the server here to retrieve any information needed to build
// the dialog, if necessary.
});
/**
* Issue asynchronous request for spreadsheet data.
* From gist.github.com/mogsdad/60dcc4116ed74fceb5f9
*/
function sendQuery() {
google.script.run
.withSuccessHandler(drawDashboard)
.withFailureHandler(function(msg) {
// Respond to failure conditions here.
$('#main-heading').text(msg);
$('#main-heading').addClass("error");
$('#error-message').show();
})
.getSpreadsheetData();
}
/**
* Callback function to generate visualization using data in response parameter.
* From gist.github.com/mogsdad/60dcc4116ed74fceb5f9
*
* @param {Object[][]} Two-Dim array of visualization data
*/
function drawDashboard(response) {
$('#main-heading').addClass("hidden");
if (response == null) {
alert('Error: Invalid source data.')
return;
}
else {
// Transmogrify spreadsheet contents (array) to a DataTable object
var data = google.visualization.arrayToDataTable(response,false);
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard-div'));
var table = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'table-div'
});
var categoryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'selector-div',
'options': {
'filterColumnLabel': 'Category'
}
});
var subCategoryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'selector1-div',
'options': {
'filterColumnLabel': 'Category'
}
});
// Set up dependencies between controls and charts
dashboard.bind([categoryPicker,subCategoryPicker], table);
// Draw all visualization components of the dashboard
dashboard.draw(data);
}
}
</script>
I do not need the Numerical Filter, all I need is something analagous to a cascading dropdown + table.
I would appreciate any pointers. Where am I going wrong? I don't think the issue is in the JS.html file - it's probably something to do with the acquisition of data from the Google sheet.
Upvotes: 1
Views: 999
Reputation: 61212
first, don't need both chart libraries, jsapi
& loader.js
according to the release notes...
The version of Google Charts that remains available via the
jsapi
loader is no longer being updated consistently. Please use the new gstaticloader.js
from now on.
next, a callback is being set to a function that does not exist...
here --> google.charts.setOnLoadCallback(drawChart);
recommend setup similar to following...
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
// Load the Visualization API and desired package(s).
google.charts.load('45', {
callback: sendQuery,
packages: ['controls', 'corechart']
});
/**
* Issue asynchronous request for spreadsheet data.
* From gist.github.com/mogsdad/60dcc4116ed74fceb5f9
*/
function sendQuery() {
google.script.run
.withSuccessHandler(drawDashboard)
.withFailureHandler(function(msg) {
// Respond to failure conditions here.
$('#main-heading').text(msg);
$('#main-heading').addClass("error");
$('#error-message').show();
})
.getSpreadsheetData();
}
/**
* Callback function to generate visualization using data in response parameter.
* From gist.github.com/mogsdad/60dcc4116ed74fceb5f9
*
* @param {Object[][]} Two-Dim array of visualization data
*/
function drawDashboard(response) {
$('#main-heading').addClass("hidden");
if (response == null) {
alert('Error: Invalid source data.')
return;
}
else {
// Transmogrify spreadsheet contents (array) to a DataTable object
var data = google.visualization.arrayToDataTable(response,false);
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard-div'));
var table = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'table-div'
});
var categoryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'selector-div',
'options': {
'filterColumnLabel': 'Category'
}
});
var subCategoryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'selector1-div',
'options': {
'filterColumnLabel': 'Category'
}
});
// Set up dependencies between controls and charts
dashboard.bind([categoryPicker,subCategoryPicker], table);
// Draw all visualization components of the dashboard
dashboard.draw(data);
}
}
</script>
EDIT
working example using query class --> google.visualization.Query
google.charts.load('45', {
callback: sendQuery,
packages: ['controls', 'corechart']
});
function sendQuery() {
var url = 'https://docs.google.com/spreadsheets/d/1-EE_WDD6QYi257_utUf_D0v5e9Gf8Lj5tETPqqllvxk/edit#gid=0';
new google.visualization.Query(url).send(function (response) {
if (response.isError()) {
console.log('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
} else {
drawDashboard(response.getDataTable());
}
});
}
function drawDashboard(data) {
$('#main-heading').addClass("hidden");
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard-div'));
var table = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'table-div'
});
var categoryPicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'selector-div',
options: {
filterColumnLabel: 'Category'
}
});
var subCategoryPicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'selector1-div',
options: {
filterColumnLabel: 'Category'
}
});
dashboard.bind([categoryPicker,subCategoryPicker], table);
dashboard.draw(data);
}
.hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<h1 id="main-heading">Loading...</h1>
<div id="dashboard-div">
<div id="control-div">
<div id="selector-div">
</div>
<div id="selector1-div">
</div>
</div>
<div id="charts-div">
<div id="table-div">
</div>
</div>
</div>
<div class="hidden" id="error-message">
</div>
Upvotes: 2