ImportHTML won't update data - google-apps-script

I'm trying to use ImportHTML in Google Spreadsheets to update data regularly. The standard ImportHTML-code updates once an hour which is too slow, so I found some Google Script to do it every minute. (I should mention I'm not a developer so I'm kinda operating blind)
However, the script doesn't replace the old data with the new data (which is the idea). I need to remove all data from the spreadsheet for it to update the information. It seems to me te script is executing, but simply doesn't overwrite when cells are already filled. This is the Script I'm using:
function myFunction() {
var sh = SpreadsheetApp.getActiveSheet();
var r = "A1";
var insertDataOption = 'overwrite';
var f = '=ImportHTML("URL";"table";1)';
sh.getRange(r).setFormula(f) .onChange;
}
I hope you can help, thankS

If you add the same formula it might not not trigger a IMPORTHTML update. To make it work, first you could to clear the cell holding the IMPORTHTML formula, in this case A1, force the spreadsheet update, then add the formula.
function myFunction() {
var sh = SpreadsheetApp.getActiveSheet();
var r = "A1";
var insertDataOption = 'overwrite';
var f = '=ImportHTML("URL";"table";1)';
var range = sh.getRange(r);
range.clear();
SpreadsheetApp.flush();
range.setFormula(f);
}
By the other hand if you are already using Google Apps Script, instead of using IMPORTHMTL you could use the Fetch Service to to the same job. This will require more coding but you will have more control over how frequently is updated your spreadsheet.
Resources
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#flush
Related (More recent first)
Google Sheets IMPORTHTML
ImportHTML recalculation by the minute
Script to refresh data with IMPORTHTML in Google Sheets
Trigger importHTML in Google Apps Script
Importing javascript table into Google Docs spreadsheet

Related

Google Sheets Apps Script to copy (GoogleFinance) data archive via appendRow

I'm using in Sheets the GoogleFinance-API to get the current $/€ exchange course.
I'm archiving this data via an apps script - reading out the fields and writing those back in the sheet using appendRow - for testing purposes I did it on a minute interval...
It worked for about 10 rows - after this it writes instead of the stock-exchange value a date '30.12.1899 23:41:33' in the field (the logs in apps scripts are fin though) - have no clue where it comes from and what I'm doing wrong here - please have a look at the screen grabs
function saveData() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = sheet.getRange(5,1,1,2).getValues();
var time = data[0][0];
var stock = data[0][1];
Logger.log(time+" ::: "+stock);
sheet.appendRow(data[0]);
Logger.log(data);
}
just added the images here - stackoverflow is not very intuitive for 1st time users.

Creating a backup of data entered into a sheet via Google App Scripts

I have a spreadsheet where users can enter data and then execute a function when clicking on a button. When the button is clicked it logs the time and entered data in a new row on another sheet in that spreadsheet.
To make sure that sheet is not accidentally edited by the users I want to create a non-shared backup of that data.
I import the range to another spreadsheet, but just importing the range means that if the original sheet is edited/erased that data will also be edited/erased, so I wrote the following script to log the changes as they come in.
function onEdit(event){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var incomingSheet = ss.getSheetByName('Incoming');
var lastRow = incomingSheet.getLastRow();
var incomingData = incomingSheet.getRange(lastRow,1,1,7);
var permanentSheet = ss.getSheetByName('PermanentLog')
var newdataRow = permanentSheet.getLastRow();
incomingData.copyTo(permanentSheet.getRange(newdataRow+1,1));
}
This works when Run from the Apps Script Editor, however, when I enter new data and click the button on the original spreadsheet, it logs the data to the log sheet there, and the range is imported to the 'Incoming' sheet of the new Spreadsheet, but the data is not copied over to the 'Permanent Log' sheet (unless I Run it manually from within the Apps Script Editor). It also works if I remove the ImportRange function from the first sheet and then just manually enter data in on the 'Incoming' sheet.
So does this mean new rows from an Imported Range do not trigger onEdit? What would be the solution? I don't want to run this on a timed trigger, I want to permanently capture each new row of data as it comes in.
Also, am I overlooking a more elegant and simple solution to this whole problem?
Thank you for your time.
This function will copy the data to a new Spreadsheet whenever you edit column 7 which I assume is the last column in your data. It only does it for the sheets that you specify in the names array. Note: you cannot run this from the script editor without getting an error unless you provide the event object which replaces the e. I used an installable onEdit trigger.
The function also appends a timestamp and a row number to the beginning of the archive data row
function onMyEdit(e) {
e.source.toast('entry');//just a toast showing that the function is working for debug purposes
const sh = e.range.getSheet();//active sheet name
const names = ['Sheet1', 'Sheet2'];//sheetname this function operates in
if (~names.indexOf(sh.getName()) && e.range.columnStart == 7) {
const ass = SpreadsheetApp.openById('ssid');//archive spreadsheet
const ash = ass.getSheetByName('PermanentLog');//archive sheet
let row = sh.getRange(e.range.rowStart, 1, 1, 7).getValues()[0];
let ts = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy/MM/dd HH:mm:ss");//timestamp
row.unshift(ts, e.range.rowStart);//add timestamp and row number to beginning
Logger.log(row);//logs the row for debug purposes
ash.appendRow(row);//appends row to bottom of data with ts and row
}
Logger.log(JSON.stringify(e));
}
Restrictions
Script executions and API requests do not cause triggers to run. For example, calling Range.setValue() to edit a cell does not cause the spreadsheet's onEdit trigger to run.
https://developers.google.com/apps-script/guides/triggers
So yeah, as far as I understand you it can't be done that way.

Can I add a formula to a google form response using Apps Script?

Apologies as I am a beginner to coding. I am interested in using Google Apps Script to automate the analysis of a Google Form response.
The simple example I have is for the spreadsheet of responses for a form asking people:
1) how many players there were?
2) where they finished [1st, 2nd, etc,]
On submission of the form I want to run a script that calculates how may points they received and inserts this value in the next available column (column E in this example).
I have tried writing my first Apps Script to automate this process, but without success.
SAMPLE CODE:
function onFormSubmit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Form Responses Master");
var players = e.values[2];
var place = e.values[3];
var positionPoints = e.values[4];
var positionPoints = (players - place + 1);
return positionPoints;
}
I know there are workarounds available by creating duplicate pages, but I was hoping someone might be able to advise me on how to code a solution in App Scripts, in the hope I might get a better understanding of the coding process.
You can write your appscript in the response collector spreadsheet itself instead of writing your code in form's script editor.
So, go to your response sheet and paste this code.
function myFunction()
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses Master");
var rowNo = sheet.getLastRow();
var colNo = sheet.getLastColumn();
sheet.getRange(rowNo, colNo).setValue("=(C"+rowNo+"-D"+rowNo+")+1");
}
Now, go to Resources -> Current project triggers. Click on add new and set these values in drop downs: myFunction - From Spreadsheet - On form submit.
And you are done. Whenever a new response is submitted, position points will be calculated automatically.
Here,
variable sheet gets your active spreadsheet for different sheet operations which you can perform.
rowNo and colNo as seen in the code, simply fetches the value of last row/column respectively of spreadsheet in which something is written.
And, to set formula in column 'E', you can use setValue. Hence, "=(C"+rowNo+"-D"+rowNo+")+1" will be converted to (C2-D2)+1 in case of second row and so on for next rows.
getRange is simply used to tell the script that write formula inside particular cell.

How to merge a large number of form response sheets into one master sheet. (Google Sheets)

I have a spreadsheet in which I have the form response sheets from a large number of forms (quizzes). As all the forms contain the same format, number and order of questions I want to collect them all into one sheet.
I know this can be done using the query({sheet1!range,sheet2!range...}) But the size of this query would be huge (have over 25 forms!) and it would require me to fiddle around with this formula every time I add a new form.
What i initially investigated was creating a list of sheets in a range and then tried to get arrayformula query to run through that list using indirect. This however did not work and after asking on this forum have been told that that cannot be done.
I was advised to look into scripts and have spent all weekend trying to find a script that can do this. I have however failed.
I need the script to copy the last row of a form response sheet to the bottom of a master sheet. I would like the script to do this to all response sheets (I have a naming format for sheets that would allow the script to easily see which sheets to incorporate). I would imagine I need to use the onSubmit() function but not sure.
Overview
I don't think that using a on submit trigger is a good idea because there are several forms involved and a large number of responses. By the other hand could be conflicts if several responses are submitted very close. IMHO a better approach is to run the script by demand (manually) or by using a time-driven trigger.
As Google Apps Script execution time should not exceed six minutes1, instead of checking each sheet for new responses I think that a better approach is to clear the master sheet and append all the sheet responses at once. This could work if there will no be notes, comments, custom formats, data validations or data changes applied directly on the master sheet.
Script
Below is a script that joins the content of form responses sheets that are in the same spreadsheet to a sheet named 'Master'. It could be easily adapted, I think.
It's assumed that the spreadsheet only contains form responses sheets and the 'Master' sheet.
/**
* Joins the data from form responses sheets on a master responses sheet.
* Assumes that the master sheet has the form response headers and
* that there aren't extra columns.
*/
function joinSheetsData() {
// Initialize loop variables
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var masterName = 'Master'; // Change this.
var masterSheet = ss.getSheetByName(masterName);
var headers = [masterSheet.getDataRange().getValues()[0]];
var masterdata = [];
// Loop to append form responses from all response sheets to one array.
for(var i = 0; i < sheets.length; i++){
if(sheets[i].getName() != masterSheet.getName()){
var data = sheets[i].getDataRange().getValues();
data.splice(0,1);
masterdata = append(masterdata,data);
}
}
// Clear the master sheet.
masterSheet.clear();
// Add the headers to the master sheet.
var masterheadersRow = masterSheet.getRange(1, 1, 1,
masterdata[0].length);
masterheadersRow.setValues(headers);
// Send the resulting array to the master sheet.
var masterdataRange = masterSheet.getRange(2, 1, masterdata.length,
masterdata[0].length);
masterdataRange.setValues(masterdata);
}
/*
* Auxiliary function to append 2D arrays.
*/
function append(a,b){
for(var i = 0; i<b.length; i++){
a.push(b[i]);
}
return a;
}

Edit a Google Spreadsheet using Google Apps Script

I am trying to edit a google spreadsheet using google apps script. Basically, I have a cell in the spreadsheet that has the value "Pending Approval" in it. When the script is executed, I want it to change the value in that cell to "Approved". Is there a simple way to do this?
.getRange and .setValue are the methods you will want to use in whatever you are trying to do. This little function will just take the cell notation as the first argument, and then the value you want to set as the second.
function setCellValue(cellName, value) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getRange(cellName);
cell.setValue(value);
}
setCellValue("A1","Approved");