Google Visualization API Not Respecting GID or Sheet Parameter - javascript

I'm using the Google Visualization Javascript API to load a Chart from Google Sheets and display it in a div. My app is hosted on Google App Engine. I provide the URL to the sheet with the parameter gid=1 to specify the second sheet but the chart the gets displayed is the first sheet. Here's my simplified code (it's basically the example code provided in the documentation):
// sheetUrl is the URL of the Google sheet, e.g., http://https://docs.google.com/a/google.com/spreadsheet/ccc?key=0AobNU9T3MusKdGFqRHNJYkFnb3RuSkt4QlE#gid=1
// divId is the id of the <div> element I'm displaying in
google.load('visualization', '1.0', {packages: ['table']});
google.setOnLoadCallback(drawChart);
function drawChart() {
var query = new google.visualization.Query(sheetUrl);
query.send(handleQueryResponse);
}
function handleQueryResponse(response) {
var data = response.getDataTable();
var table = new google.visualization.Table(document.getElementById(divId));
table.draw(data);
}
You can see the #gid=1 in the URL. I've also tried &gid=1 and &sheet='Volume', which is the name of the tab but when the page loads, the data from the first tab gets rendered.
I have noticed Google sheet urls in the form I have above but also in this form:
https://docs.google.com/spreadsheet/tq?key=0AobNU9T3MusKdGFqRHNJYkFnb3RuSkt4QlE
I haven't been able to find any documentation explicitly explaining the tq endpoint. I tried using a URL in this form but I get timeout error when trying to load the chart. Any one run into this problem or have insight in the tq thing? Thanks!
Edit 2014-02-17:
I've changed my URL to use the tq endpoint and I've tried the following parameters:
#gid=1
&gid=1
#sheet=Volume
&sheet=Volume
When I query for the url in the browser:
https://docs.google.com/spreadsheet/tq?key=0AobNU9T3MusKdGFqRHNJYkFnb3RuSkt4QlE&sheet=Volume
I get the appropriate sheet back. But when I use the Visualization API to query, I get the first sheet.

The correct URL to pass to the Visualization API that will work with the new Google Sheets is this format:
https://docs.google.com/spreadsheets/d/{key}/gviz/tq
You can use the gid query parameter to pass the ID of the worksheet you want to retrieve. So if your gid is 0, the URL would be:
https://docs.google.com/spreadsheets/d/{key}/gviz/tq?gid=0
You can find additional information regarding URL formats for both the old and new Google Sheets in this bug report.
Hope that helps.

Referencing by sheet name also works as in
https://docs.google.com/spreadsheets/d/{key}/gviz/tq?sheet=MySheetName
Make sure spreadsheet is "new" vs "old" Google Sheets. I banged my head on that one as I thought my sheet was new. Once I created a new style sheet and used donnapep answer I was working again. I then confirmed using sheet=sheetname works as well which was what I was really after.

Related

How to use Google Sheets as read-only database for Angular, without making the sheet public

I'm trying to use Google Sheets document as read-only database for my angular application.
I tried some methods to do that, but the problem with all of these methods is that they require the Sheet to be shared publicly (anyone with the link can access the sheet). But what I want is to share it with specific user using Service Account through credentials.
I'm using Angular 14
There is no reference to Angular in Google Sheets for Developers.
If you know any solution or come across an article about this topic, please share it with me.
Thank you.
Here are the steps you'll need to take in order to read from Google Sheets into Angular:
Step 1: Prepare your Google Sheet
1.) Make sure ALL the cells in your sheet are formatted as "Plain text". To do this, click in the upper-left corner of the sheet nexus where the rows and columns intersect to select all cells, then select Format > Number > Plain text from the top menu.
2.) Go to Share, then under "General Access", select "Anyone with the link", then click Done. I believe in your case that this step is optional, since you do not want the sheet to be public.
3.) Go to File > Share > Publish to web in the top menu. Set the scope of what you want to publish, then click Publish. Unfortunately in your case, this step is NOT optional!
Step 2: Fetch the Google Sheet Data
Use the following code example to fetch the raw data from your Google Sheet as plain text:
const docId = '1vLjJqvLGdaS39ccsvoU58kEWXngzV_VXtto07Ki6qVo';
const sheetId = ''; // to get a specific sheet by ID, use '&gid=###'
const url = `https://docs.google.com/spreadsheets/d/${docId}/gviz/tq?tqx=out:json${sheetId}`;
this.http.get(url, {
responseType: 'text',
}).subscribe((response: string): void => {
console.log(response);
});
Step 3: Parse the Raw Text as JSON
Use the following example to parse the raw text to JSON:
const rawJSONText = response.match(/google\.visualization\.Query\.setResponse\(([\s\S\w]+)\)/); // strip the header response
const json = JSON.parse(rawJSONText[1]);
console.log(json);
Hope this helps. Cheers!

Parsing a stringified JSON coming from a Google Sheet Web App

I'm trying to parse a stringified JSON output from a web app created from a google sheets script. I thought it couldn't be that complicated, but I've tried everything I could think of or find out online... so now asking for help if that's OK!
on the web app / Google Sheets side, the code is:
function doGet(e) {
var spreadsheet = SpreadsheetApp.openById('spreadsheetID');
var worksheet = spreadsheet.getSheetByName('Rankings C/U');
var output = JSON.stringify({ data: worksheet.getDataRange().getValues() });
return HtmlService.createHtmlOutput(output);
}
I've published the script, the web app works, I'm OK with that bit.
I've put random values on the spreadsheet: [[1,2],[3,4]] if we speak in matrix format.
on the other end, I've tried a bunch of stuff including .fetch, JSON.parse() to get the data in a usable format within the Google Sites embedded code, but the real issue is that I think I can't get to allocate the payload to a variable?
I'm using Google Sites to fetch the data.
with the basic module "<> embed", with the "by URL" option, with the following code:
https://script.google.com/macros/s/scriptID/exec
I get the following output - that looks what it should be:
{"data":[[1,2],[3,4]]}
but when trying to include this in a script module ("embed code") - no chance!
<form name="get-images">
<input name="test" id="test" value="we'll put the contents of cell A1 here">
</form>
<script>
const form = document.forms['get-images']
var usableVariable = JSON.parse("https://script.google.com/macros/s/scriptID/exec"); // here I'm trying to allocate the stringified JSON to a variable
form.elements['test'].value = usableVariable[1,1]; //allocating the first element of the parsed array
</script>
I'm pretty sure I'm missing something obvious - but now I ran out of ideas!
Thanks for any help :)
I believe your goal as follows.
In your situation, the bottom script is embedded to the Google site.
You want to retrieve the values from doGet and want to put the value of cell "B2" to the input tag.
The settings of Web Apps is Execute the app as: Me and Who has access to the app: Anyone, even Anonymous.
Modification points:
In your case, I think that return ContentService.createTextOutput(output); is suitable instead of return HtmlService.createHtmlOutput(output); in Google Apps Script.
In order to retrieve the values from doGet, in this modification, fetch is used.
You want to retrieve the cell "B2" from usableVariable[1,1];, please modify it to usableVariable[1][1];
When above points are reflected to your script, it becomes as follows.
Modified script:
Google Apps Script side:
function doGet(e) {
var spreadsheet = SpreadsheetApp.openById('spreadsheetID');
var worksheet = spreadsheet.getSheetByName('Rankings C/U');
var output = JSON.stringify({ data: worksheet.getDataRange().getValues() });
return ContentService.createTextOutput(output);
}
HTML & Javascript side:
<form name="get-images">
<input name="test" id="test" value="we'll put the contents of cell A1 here">
</form>
<script>
let url = "https://script.google.com/macros/s/###/exec";
fetch(url)
.then((res) => res.json())
.then((res) => {
const usableVariable = res.data;
const form = document.forms['get-images'];
form.elements['test'].value = usableVariable[1][1]; // usableVariable[1][1] is the cell "B2".
});
</script>
Note:
When you modified the Google Apps Script of Web Apps, please redeploy the Web Apps as new version. By this, the latest script is reflected to the Web Apps. Please be careful this.
In my environment, I could confirm that above HTML & Javascript worked in the Google site by embedding.
References:
Class ContentService
Using Fetch
Web Apps

I'm trying to get a chart from my spreadsheet to send in an email using google script, but the getAs() function isn't working

Whenever I've looked into how to email a chart, all the answers involve some variation on using the getAs function to save the chart as an image and then either inlining it or attaching it to the email. But I'm struggling to save the chart as an image in order to attach it. When I run the following code:
var chart = demandLastWeekSheet.getCharts().getAs("image/png");
I get this error:
TypeError: demandLastWeekSheet.getCharts(...).getAs is not a function (line 8, file "Code")
In fact, I get the same error if I try .getBlob(), .modify() or any other functions from here: https://developers.google.com/apps-script/reference/spreadsheet/embedded-chart.html
Surely these functions have not been deprecated? Am I doing something wrong/stupid? New to the world of apps script, any pointers welcome! Sorry also if this is a badly phrased question, also I am new to stack overflow :)
Any suggestions??
getCharts() returns EmbeddedChart[]. In your script, the method of getAs is used for an array. I think that this is the reason of your issue. In order to retrieve the blob of the chart using the method of getAs, please modify as follows.
From:
var chart = demandLastWeekSheet.getCharts().getAs("image/png");
To:
var chart = demandLastWeekSheet.getCharts()[0].getAs("image/png");
In this modification, the 1st chart in the sheet of demandLastWeekSheet is retrieved. If you want to retrieve the 2nd chart, please modify from [0] to [1].
Reference:
getCharts()

How to implement the makeApiCall() method after migrating Google Sheets API v3 to v4 with Oauth Authorization in Javascript

Google has build v4 of the Google Sheets API but the documentation of this is still at v3. There are no full examples of how to implement a simple OAuth authentication with Google Sheets API v4.
I see a migration guide here and I also see a partial example here
But a full example is nowhere to be found.
The "current" version is here and it was last updated in October 2018 without providing a v4 example.
Let's say that after I authorize the user, I'm trying to read a particular spreadsheet in workbook2 and I'm explicitly specifying what columns I need. Then I present that information with Google Visualization API.
So, here's how I do it in Google Sheets v3 legacy.
function makeApiCall() {
var queryString = encodeURIComponent('SELECT A,B,C,E,H');
var tqURL = new google.visualization.Query(
'https://docs.google.com/spreadsheets/d/*yourspreadsheetid*/gviz/tq?gid=*yourworkbookid*&headers=1&tqx=responseHandler:handleTqResponse' + '&access_token=' + encodeURIComponent(gapi.auth.getToken().access_token));
tqURL.send(handleTqResponse);
}
function handleTqResponse(resp) {
var dataTable = resp.getDataTable();
}
For v4, if I follow this partial example here, how do I convert the tqURL to a GET method? and how can I still get the response (rsp) as a DataTable()?
function makeApiCall() {
var params = {
spreadsheetId: 'my-spreadsheet-id', // all clear here
//what about workbook gid?
// The ranges to retrieve from the spreadsheet.
ranges: [], // [A:A,B:B,C:C,E:E,H:H) ????
includeGridData: false,
//no need to include the access_token here?
};
var request = gapi.client.sheets.spreadsheets.get(params);
request.then(function(response) {
console.log(response.result);
//var dataTable = responce.getDataTable(); ??
}, function(reason) {
console.error('error: ' + reason.result.error.message);
});
}
I don't believe there is an analog for the Visualization API in the Sheets API(V4). Technically, the visualization API isn't really a part of legacy Sheets API (V3). If anything its a part of the Charts API. So you should be able to continue using it.
You can even use it server-side directly in GAS (see Using Bound Google Scripts to Generate a Query Object).
You have already been able to use Sheets API.
Sheets API is enabled at API console.
The access token can be used for retrieving values from the Spreadsheet.
You want to retrieve the values of A:A,B:B,C:C,E:E,H:H from a sheet.
You want to retrieve the dataTable using getDataTable() from the values retrieved by Sheets API.
If my understanding is correct, how about this modification? In this modification, I modified your script in your question. Please think of this as just one of several answers.
Modification points:
In order to retrieve values from A:A,B:B,C:C,E:E,H:H, use the method of values.get in Sheets API.
In this case, at first, the values of A:H are retrieved and the values of the column A, B, C, E and H are retrieved.
In order to retrieve the dataTable using getDataTable(), use ChartWrapper Class.
Modified script:
function makeApiCall() {
var params = { // Modified
spreadsheetId: 'my-spreadsheet-id',
range: 'Sheet1!A:H', // Retrieve the values of "A:H".
};
var request = gapi.client.sheets.spreadsheets.values.get(params); // Modified
request.then(function(response) {
var values = response.result.values.map((e) => [e[0], e[1], e[2], e[4], e[7]]); // Added
var w = new google.visualization.ChartWrapper({dataTable: values}); // Added
var dataTable = w.getDataTable();
}, function(reason) {
console.error('error: ' + reason.result.error.message);
});
}
Note:
When the method of values.get in Sheets API is used, please use a1Notation for the range. So in this case, the range becomes Sheet1!A:H. This means "A:H" of "Sheet1".
References:
values.get
ChartWrapper Class
If I misunderstood your question and the result was not what you want, I apologize.

Appending new Google Sheets Data into BigQuery Table

So I'm new to all of this, both BigQuery and AppScript (coding in general..) and I'm learning as I go, so maybe to some my question may seem stupid. Please just hear me out.
I have created a script that loads 10 of the most recent data points into a Google Sheets doc from one of my BigQuery tables. Now, when I manually add new data points to the bottom of this table, I would like to have a load script run that uploads that new data back into BigQuery, and appends it to my original table. I read somewhere that just by inserting a new table the data is automatically appended if the table mentioned already exists. However, I haven't tested that part yet since I get stuck on an error earlier up the line..
Below is the load script I have loosely copied from https://developers.google.com/apps-script/advanced/bigquery
function loadCsv() {
var projectId = 'XX';
var datasetId = 'YY';
var tableId = 'daily_stats_testing';
var file = SpreadsheetApp.getActiveSpreadsheet();
var sheet = file.getActiveSheet().getRange("A12:AK10000").getValues();
var data = sheet.getBlob().setContentType('application/octet-stream');
var job = {
configuration: {
load: {
destinationTable: {
projectId: projectId,
datasetId: datasetId,
tableId: tableId
},
skipLeadingRows: 1
}
}
};
job = BigQuery.Jobs.insert(job, projectId, data);
var Msg = "Load started. Check status of it here:" +
"https://bigquery.cloud.google.com/jobs/%s", projectId
Logger.log(Msg);
Browser.msgBox(Msg);
return;
}
Now the error I get (in a variety of forms, since I've been testing stuff out) is that the BigQuery.Jobs function only accepts Blob data, and that the data from my current sheet (with rage A12 marking the first manually imputed row of data) is not a Blob recognizable data set.
Is there any way (any function?) I can use that will directly convert the selected data range and make it Blob compatible?
Does anyone have any recommendation on how to do this more efficiently?
Unfortunately the script has to load directly out of the current, open Spreadsheet sheet, since it is part of a larger script I will be running. Hopefully this isn't too much of a hinder!
Thanks in advance for the help :)
Is there any way (any function?) I can use that will directly convert the selected data range and make it Blob compatible?
There is actually a function that does convert objects into blob type, namely newBlob(data).
To test this I got a range from my spreadsheet and used it.
function blobTest(){
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("A1:C1");
Logger.log(range); //here, range data is of type Range object
var blob = Utilities.newBlob(range);
Logger.log(blob); //here, range data is now of type Blob object
}

Categories

Resources