I've been using google's charts API and have reached a dead end. I use the API to query a spreadsheet and return some data. For visualizations I'm using Razorflow - a JS dashboard framework - not Google Charts. Getting the data is pretty straight forward using code like this (this code should work - spreadsheet is public):
function initialize() {
// The URL of the spreadsheet to source data from.
var myKey = "12E2fE8GWuPvXJoiRZgCZUCFhRKlW69uJAm7fch71jhA"
var query = new google.visualization.Query("https://docs.google.com/spreadsheets/d/" + myKey + "/gviz/tq?sheet=Sheet1");
query.setQuery("SELECT A,B,C WHERE A>=1 LIMIT 1");
query.send(function processResponse(response) {
var KPIData = response.getDataTable();
var KPIName = [];
myNumberOfDataColumns = KPIData.getNumberOfColumns(0) - 1;
for (var h = 0; h <= myNumberOfDataColumns ; h++) {
KPIName[h] = KPIData.getColumnLabel(h);
};
});
};
google.charts.setOnLoadCallback(initialize);
The above will create an array holding the column labels for column A,B and C.
Once the data is fetched I want to use the data for my charts. Problem is, I need to have the data ready before I create the charts. One way I have done this, is creating the chart before calling google.charts.setOnLoadCallback(initialize)
and then populate the charts with data from inside the callback. Like this:
//create dashboard
StandaloneDashboard(function (db) {
//create chart - or in this case a KPI
var firstKPI = new KPIComponent();
//add the empty component
db.addComponent(firstKPI);
//lock the component and wait for data
firstKPI.lock();
function initializeAndPopulateChart() {
// The URL of the spreadsheet to source data from.
var myKey = "12E2fE8GWuPvXJoiRZgCZUCFhRKlW69uJAm7fch71jhA"
var query = new google.visualization.Query("https://docs.google.com/spreadsheets/d/" + myKey + "/gviz/tq?sheet=Sheet1");
query.setQuery("SELECT A,B,C WHERE A>=1 LIMIT 1");
query.send(function processResponse(response) {
var KPIData = response.getDataTable();
var KPIName = [];
myNumberOfDataColumns = KPIData.getNumberOfColumns(0) - 1;
for (var h = 0; h <= myNumberOfDataColumns ; h++) {
KPIName[h] = KPIData.getColumnLabel(h);
};
//use label for column A as header
firstKPI.setCaption(KPIName[0]);
//Set a value - this would be from the query too
firstKPI.setValue(12);
//unlock the chart
firstKPI.unlock();
});
};
google.charts.setOnLoadCallback(initializeAndPopulateChart);
});
It works but, I would like to separate the chart functions from the data loading. I guess the best solution is to create a promise. That way I could do something like this:
//create dashboard
StandaloneDashboard(function (db) {
function loadData() {
return new Promise (function (resolve,reject){
//get the data, eg. google.charts.setOnLoadCallback(initialize);
})
}
loadData().then(function () {
var firstKPI = new KPIComponent();
firstKPI.setCaption(KPIName[0]);
firstKPI.setValue(12);
db.addComponent(firstKPI);
})
});
As should be quite obvious, I do not fully understand how to use promises. The above does not work but. I have tried lots of different ways but, I do not seem to get any closer to a solution. Am I on the right track in using promises? If so, how should i go about this?
Inside a promise you need to call resolve
or reject
function when async job is done.
function loadData() {
return new Promise (function (resolve,reject){
query.send(function() {
//...
err ? reject(err) : resolve(someData);
});
})
}
And then you can do
loadData().then(function (someData) {
//here you can get async data
}).catch(function(err){
//here you can get an error
});
});