I have set up a script to pull in data from a JSON API into a Google Sheet. I have set it to refresh by adding a third parameter which isn't used in the API call but is linked to a cell which another script adds the current time to. This ensures that the API is called regularly.
We are then using this Google Sheet to input data into Google Ads.
It all seems to function correctly, however, when the sheet has been closed for a while (e.g. overnight) and Google Ads tries to update from the sheet, it imports #NAME? instead of the correct API value.
I have set up another script which records the API values at regular intervals. This seems to record the values correctly, suggesting that the API calls are working whilst the sheet is closed.
// Make a POST request with a JSON payload.
// Datetime parameter isn't use in API call but is used to refresh data
function TheLottAPI(game,attribute,datetime) {
var data = {
'CompanyId': 'GoldenCasket',
'MaxDrawCount': 1,
'OptionalProductFilter': [game]};
Logger.log(data);
var options = {
'method' : 'post',
'contentType': 'application/json',
// Convert the JavaScript object to a JSON string.
'payload' : JSON.stringify(data)};
var response = UrlFetchApp.fetch('https://data.api.thelott.com/sales/vmax/web/data/lotto/opendraws', options);
Logger.log('output: '+ response);
// Convert JSON response into list
var json = JSON.parse(response)
var drawList=json ["Draws"];
// Extract attribute from list
for(var i=0;i<drawList.length;i++)
{var value=drawList[i][attribute];}
Logger.log(value)
return value;
SpreadsheetApp.flush();
};
// Set date & time to refresh API call
function RefreshTime() {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Attributes").getRange("K4").setValue(new Date().toTimeString());
}
The correct numeric values from the API should be shown, rather than the #NAME? error.
I have checked that the API call is functioning correctly by using another script to copy the current values. The API was updating at the appropriate times overnight.
function RecordDraws() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Draw Amounts");
var source = sheet.getRange("A3:D3");
var values = source.getValues();
values[0];
sheet.appendRow(values[0]);
};
This is my guess
Google Sheets custom functions definitions are loaded when the spreadsheet is opened by using the Google Sheets UI, then formulas are calculated and as custom functions are already defined they are calculated correctly. If the spreadsheet isn't opened this way the custom functions definitions aren't loaded thus the spreadsheet doesn't know what to do with that function and returns #NAME?
If you are already running a script that updates some values, enhance that script to do the calculations that does your custom function.
Try converting this
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Attributes").getRange("K4").setValue(new Date().toTimeString());
Into this:
SpreadsheetApp.openById("id").getSheetByName("Attributes").getRange("K4").setValue(new Date().toTimeString());
Because I don't think there is an "active sheet" when the Spreadsheet it's closed or the method is called from the API.
Related
I've setup a google app script that would be triggered from an external system. This script would fetch the details from the third party system and add them to google sheet row.
function doPost(request) {
try{
var jsonString = request.postData.getDataAsString(); //get the request from KF as JSON String
setLog("\n postData*********************"+jsonString+"************************************* \n");
setLog("before the row append");
ss.appendRow([jsonString["Name"], jsonString["Age"], jsonString["Contact"]]);
setLog("After the row append");
var returnJson = '{"status": "success"}';
//used to send the return value to the calling function
setLog("/n returnJson****************************"+returnJson+"************************************* /n")
return ContentService.createTextOutput(returnJson).setMimeType(ContentService.MimeType.JSON);
}
There's absolutely no errors or warnings, but somehow it keeps adding the blank rows into the sheet.
Note: setLog() is a function where I print the values into google doc for debugging.
Maybe the reason your script is not working has to do with the value of jsonString.
I could not find any reference to request.postData.getDataAsString() inside GAS Documentation, so maybe you are trying to call a method on an object which does not support it, which would not raise an Error, but would return undefined.
One quick way to debug this would be to LOG the value (using your custom function or Logger.log(jsonString)) BEFORE you call .appendRow(). Then, you can verify if your variable has the value you expect it to have.
On the other hand, my suggestion is to use this method:
var jsonString = JSON.parse(request.postData.contents) //Gets the content of your request, then parses it
This method is present in the Documentation, and has been consistently working on all of my projects.
I think you should sort the coulmns with google app script. Write this code after ss.appendRow. The column will be sorted and all blank rows gets down.
// Sorts the sheet by the first column, ascending
ss.sort(1)
or if errors try this one also
var fl = SpreadsheetApp.getActiveSpreadsheet();
var sheet = fl.getSheets()[0];
fl.sort(1)
I have a Google Sheet with 5 columns (First Name, Address, SKU, Quote, Status).
I have an apps script function (createQuote) which looks at the above variable's values from google sheet row and create a google document quote replacing the variables to values.
I use Zapier to insert row into my above google sheet.
What am struggling with-:
I need a way to trigger my createQuote function right when a new row is inserted via zapier (Google Sheet API call).
I tried playing with triggers but couldn't make it, any help is appreciated.
thank you
here is the code for my function-
function quoteCreator(){
docTemplate = "googledocidgoeshere"
docName = "Proposal"
var sheet = SpreadsheetApp.getActive().getSheetByName("Main")
var values = sheet.getDataRange().getValues()
var full_name = values[1][0]
var copyId = DriveApp.getFileById(docTemplate).makeCopy(docName+" for "+full_name).getId()
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document’s body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys/tags,
copyBody.replaceText("keyFullName", full_name);
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
// put the link of created quote in the quote column
var url = DocumentApp.openById(copyId).getUrl()
var last = sheet.getRange(2, 7, 1, 1).setValue(url)
}
Note-: I haven't put the loop yet in above, i'll do that once it starts working as per my requirements.
Changes made via Sheets API or Apps Script do not fire onEdit triggers. I give two workarounds for this.
Web app
Have whatever process updates the sheet also send a GET or POST request to your script, deployed as a web application. As an example, a GET version might access https://script.google.com/.../exec?run=quoteCreator
function doGet(e) {
if (e.parameter.run == "quoteCreator") {
quoteCreator();
return ContentService.createTextOutput("Quote updated");
}
else {
return ContentService.createTextOutput("Unrecognized command");
}
}
The web application should be published in a way that makes it possible for your other process to do the above; usually this means "everyone, even anonymous". If security is an issue, adding a token parameter may help, e.g., the URL would have &token=myToken where myToken is a string that the webapp will check using e.parameter.token.
GET method is used for illustration here, you may find that POST makes more sense for this operation.
Important: when execution is triggered by a GET or POST request, the methods getActive... are not available. You'll need to open any spreadsheets you need using their Id or URL (see openById, openByUrl).
Timed trigger
Have a function running on time intervals (say, every 5 minutes) that checks the number of rows in the sheet and fires quoteCreator if needed. The function checkNewRows stores the number of nonempty rows in Script Properties, so changes can be detected.
function checkNewRows() {
var sp = PropertiesService.getScriptProperties();
var oldRows = sp.getProperty("rows") || 0;
var newRows = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Main").getLastRow();
if (newRows > oldRows) {
sp.setProperty("rows", newRows);
quoteCreator();
}
}
This question already has an answer here:
No permission to call msgBox in Google Apps Scripting
(1 answer)
Closed 6 years ago.
This is a Google Apps Script that pulls JSON data into Google Sheets.
The code is:
function pullJSON() {
var url="https://api.myjson.com/bins/4610d"; // publicly available json
var response = UrlFetchApp.fetch(url); //
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var dataAll = JSON.parse(response.getContentText());
var dataSet = dataAll;
var rows = [],
data;
for (i = 0; i < Object.keys(dataSet).length; i++) {
data = dataSet[Object.keys(dataSet)[i]];
rows.push([data.name]); //JSON entities here
}
dataRange = sheet.getRange(1, 1, rows.length, 1);
dataRange.setValues(rows);
}
In Google Sheets, I called the function by entering =pullJSON() into a cell. It shows the error:
"You do not have permission to call setValues(line 20)" which is referring to the line : dataRange.setValues(rows);
and produces "undefined" result in Cells A1,A2,A3.
The JSON data source is simply this:
{"id":1,"name":"A green door","price":12.5}
The purpose of doing these is to be able to convert the JSON data into table form in google sheets.
Much of the above closely followed the content in this thread:
"The coordinates or dimensions of the range are invalid" - Google Apps Script and JSON Data
Will be very grateful for any guidance on this question please.
A custom function cannot affect cells other than those it returns a
value to. In other words, a custom function cannot edit arbitrary
cells, only the cells it is called from and their adjacent cells. To
edit arbitrary cells, use a custom menu to run a function instead.
from the documentation: https://developers.google.com/apps-script/guides/sheets/functions
I don't know your exact use-case but it looks like it would be possible to run your function from a custom menu.
I make a Facebook API call in Google scripts to get the share count for a URL. It appears that the number (e.g. 31) is being found correctly, but when I pass it to Sheets, it shows e.g. 30/01/1900 in the sheets box.
My appScript code is:
function getShareCount(url) {
var url = "https://any.org/111";
var inputurl = "https://graph.facebook.com/v2.1/?id=" + url + "&access_token=XXXXXXXX";
var response = UrlFetchApp.fetch(inputurl);
var response = JSON.parse(response.getContentText());
var response = response.share.share_count;
Utilities.sleep(500);
return response;
}
and the spreadsheet box has: "=getShareCount(B2)"
If I purposefully break the code and run the debugger in script Apps, I can see that script apps is getting a response with Number: 31. If I change to e.g. "response.id", the URL is returned into sheets as expected. The same with other parts of the object. Those are strings, and this is a number. I can't work out what sort of object sheets is receiving, nor what method I can use to simply show the number `311.
Any ideas? Thanks!
It seems that your cell has a custom format of Date. Select the cells you want to format and click Format > Number > Automatic
I want to know if and how is it possible to get data from specific cells of a Google spreadsheet without publishing the sheet as public using HTTP GET request to fetch data in JSON format.
I am not totally sure if this is what you are looking for, but you could just create a doGet() that returns a JSON object and then publish your project as a Webapp. Then make get requests to that URL.
function doGet() {
var cell = SpreadsheetApp
.openById('SPREADSHEET ID HERE')
.getActiveSheet()
.getRange('A1')
.getValue();
var stringified = JSON.stringify({cellValue: cell});
return ContentService.createTextOutput(stringified);
}
EDIT: You could even put in some URL parameters and make it return specific cells. Read more here.