ImportXML fails - alternative? - google-apps-script

I've created a spreadsheet to pull in data from two river gauges near my house to try and follow their relationship to the water level as it passes us, (it's an old mill) since more and more the country seems to be flooding!
Basically the sheet works perfectly but not when the spreadsheet isn't open/when I close the laptop. I thought openById and getSheetByName would solve this but I'm having no luck.
The ImportXML commands that I construct just return N/A when the sheet is not open. The script is on a timed trigger every 15mins. I have another basic script that rewrites the contents of the cells as values so that there is only one row of ImportXML commands at a time.This script is also on a timed trigger.
I've pasted the scripts below - apologies if they're not very eloquent, these are my first attempts!
function fetchData() {
var sheet = SpreadsheetApp.openById("0AgG7jQSg2ljFdGNpbFRjUTA1LXJwdmtPcmxkQnZpUHc").getSheetByName("River Levels");
var bredURL = "http://www.environment-agency.gov.uk/homeandleisure/floods/riverlevels/120743.aspx?stationId=4004";
var belURL = "http://www.environment-agency.gov.uk/homeandleisure/floods/riverlevels/120743.aspx?stationId=4002";
var ssBredLevel = "substring((//div[#class='plain_text']/p)[2],35,4)";
var ssBelLevel = "substring((//div[#class='plain_text']/p)[2],31,4)";
var ssTime = "substring(//div[#class='plain_text']/p[2],34,5)";
var ssDate = "substring(//div[#class='plain_text']/p[2],43,10)";
var commandBredLevel = "ImportXML(\"" + bredURL + "\",\"" + ssBredLevel + "\")"; // build ImportXML() command
var commandBredTime = "ImportXML(\"" + bredURL + "\",\"" + ssTime + "\")"; // build ImportXML() command
var commandBredDate = "ImportXML(\"" + bredURL + "\",\"" + ssDate + "\")"; // build ImportXML() command
var commandBelLevel = "ImportXML(\"" + belURL + "\",\"" + ssBelLevel + "\")"; // build ImportXML() command
var commandBelTime = "ImportXML(\"" + belURL + "\",\"" + ssTime + "\")"; // build ImportXML() command
var commandBelDate = "ImportXML(\"" + belURL + "\",\"" + ssDate + "\")"; // build ImportXML() command
sheet.appendRow(['Bredwardine',' ',' ',' ',' ','Belmont',' ',' ',' ',' ','=now()']); // append row
var lastrow = sheet.getLastRow(); // define last row
var bredLevel = sheet.getRange(lastrow, 2); // define ImportXML cell
var bredTime = sheet.getRange(lastrow, 3); // define ImportXML cell
var bredDate = sheet.getRange(lastrow, 4); // define ImportXML cell
var belLevel = sheet.getRange(lastrow, 7); // define ImportXML cell
var belTime = sheet.getRange(lastrow, 8); // define ImportXML cell
var belDate = sheet.getRange(lastrow, 9); // define ImportXML cell
bredLevel.setFormula(commandBredLevel);
bredTime.setFormula(commandBredTime);
bredDate.setFormula(commandBredDate);
belLevel.setFormula(commandBelLevel);
belTime.setFormula(commandBelTime);
belDate.setFormula(commandBelDate);
writeFormats();
}
function writeRows() {
var sheet = SpreadsheetApp.openById("0AgG7jQSg2ljFdGNpbFRjUTA1LXJwdmtPcmxkQnZpUHc").getSheetByName("River Levels");
var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());
range.setValues(range.getValues());
};
function writeFormats() {
var sheet = SpreadsheetApp.openById("0AgG7jQSg2ljFdGNpbFRjUTA1LXJwdmtPcmxkQnZpUHc").getSheetByName("River Levels");
var lastcol = sheet.getLastColumn(); // define width of sheet
var lastrow = sheet.getLastRow(); // define last row
var penrow = lastrow-1; // define penultimate row
var formatting = sheet.getRange(penrow,1,1,lastcol); // fetch formatting from penultimate row
formatting.copyFormatToRange(sheet,1,lastcol,lastrow,lastrow); // paste formatting to last row
};

Related

Combine multiple Google sheet scripts

I have been trying for weeks now to solve this issue but did not have any luck (I am pretty new to Google Scripting). So I am posting here hoping some of you managed to solve this before me !
I have multiple scripts in Google sheets and I would like to put them all together to run everything on a schedule.
The scripts are running well separately but not together. I see mostly conflict between script 2 and 3
Basically this is to get datas from an URL, and clean them. Here is a description of the script :
1 - Get the data from an URL
2 - Clean column 6
3 - Clean column 3
4 - Change number format
Here is the script :
function importCSVFromWeb() {
// Provide the full URL of the CSV file.
var csvUrl = "https://mycsvdata.testsite";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
// 2 - CLEAN CATEGORIES
function clean() {
var startTime = new Date().getTime();
var deleteSelectedRows = removeThenSetNewVals();
var runTime = (new Date().getTime() - startTime) / 1000;
Logger.log("Runtime is: " + runTime + " seconds");
};
function removeThenSetNewVals(){
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var range = sheet.getDataRange();
var pattern = new RegExp("Accessories|case|pouch...");
var columnToSearch = 5;
var newRangeVals = range.getValues().filter(r => r[0] && !pattern.exec(r[columnToSearch]))
range.clearContent();
var numRows = newRangeVals.length;
var newRange = sheet.getRange(1,1, numRows, newRangeVals[0].length).setValues(newRangeVals);
var maxRows = sheet.getMaxRows();
sheet.deleteRows(numRows + 1, maxRows - numRows);
};
// 3 - CLEAN NAME
function clean2() {
var startTime = new Date().getTime();
var deleteSelectedRows = removeThenSetNewVals2();
var runTime = (new Date().getTime() - startTime) / 1000;
Logger.log("Runtime is: " + runTime + " seconds");
};
function removeThenSetNewVals2(){
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var range = sheet.getDataRange();
var pattern = new var pattern = new RegExp("Accessories|case|pouch...");
var columnToSearch = 2;
var newRangeVals = range.getValues().filter(r => r[0] && !pattern.exec(r[columnToSearch]))
range.clearContent();
var numRows = newRangeVals.length;
var newRange = sheet.getRange(1,1, numRows, newRangeVals[0].length).setValues(newRangeVals);
var maxRows = sheet.getMaxRows();
sheet.deleteRows(numRows + 1, maxRows - numRows);
};
// 4 - CLEAN PRICE
function decimal(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var cell = sheet.getRange("D1:D");
// Always show 3 decimal points
cell.setNumberFormat("00");
}
Thank you very much for any help !
There are two methods that might help you - Spreadsheet.flush() and Lockservice. I cannot tell for sure if it will work without having the insight into your code, but you can try. Wrap each of your method calls into:
const lock = LockService.getScriptLock()
try{
lock.waitLock(30000)
method() // run your method here
SpreadsheetApp.flush()
} finally{
lock.releaseLock()
}
I am curious what you mean by run them together. But it is easy enough to have one function call the other functions and then using a trigger, set sheets to run the main function on the schedule you want
function daily() {
importCSVFromWeb();
clean();
removeThenSetNewVals();
clean2();
removeThenSetNewVals2();
decimal();
}

Copy paste if Date = Today Google Sheets API

I am new to google script (and Javascript in general) and am trying to create a "Macro" which loops through a large table of data (Titled "Form response 1"), searches each row to see if the data in the 'To-arrive-date" column matches todays date. If the dates match, I want to copy-paste it into another sheet titled "Email". Below is the script I have written so far, but I keep getting an error stating that an unexpected "Var" is on line 15. However, I thought this var needed to be there for the variable "SrcRange"? Any help would be wonderful, thank you.
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = sSheet.getSheetByName("Form Responses 1");
var tarSheet = sSheet.getSheetByName("Email");
var lastRow = srcSheet.getLastRow();
var Tsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses 1");
var date = new Date();
Tsheet.getRange(2, 11).setValue(date);
for (var i = 2; i <= lastRow; i++) {
var cell = srcSheet.getRange("C" + i);
var val = cell.getValue();
if (val == SrcSheet.getRange(2, 11).getValues()
var srcRange = srcSheet.getRange("A" + i + ":F" + i);
var tarRow = tarSheet.getLastRow();
tarSheet.insertRowAfter(tarRow);
var tarRange = tarSheet.getRange("A" + (tarRow+1) + ":F" + (tarRow+1));
srcRange.copyTo(tarRange);
}
}
-Evan
Issue
Your IF statement inside the loop is incomplete. It lacks closing parenthesis as well as opening curly brace. I also noticed and commented out unnecessary codes and corrected a few specifically with regards to new Date() method.
Solution
Please see modified code below. Note that I only modified a few part of the code to make it work. I haven't done any optimization(if applicable). Also, this code is working fully on my end.
function myFunction() {
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = sSheet.getSheetByName("Form Responses 1");
var tarSheet = sSheet.getSheetByName("Email");
var lastRow = srcSheet.getLastRow();
var tSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses 1");
var date = new Date().toDateString();
tSheet.getRange(2, 11).setValue(date);
for (var i = 2; i <= lastRow; i++) {
var cell = srcSheet.getRange("C" + i);
var val = new Date(cell.getValue().toString()).toDateString();
Logger.log(val+" "+date)
if (val == date){
Logger.log("test")
var srcRange = srcSheet.getRange("A" + i + ":F" + i);
var tarRow = tarSheet.getLastRow();
// tarSheet.insertRowAfter(tarRow);
var tarRange = tarSheet.getRange("A" + (tarRow+1) + ":F" + (tarRow+1));
srcRange.copyTo(tarRange);
}
}
}

Auto Send Email When Checkbox is Checked - Google Sheet

I tried the script from Auto Email Function for Google Sheets Mobile and it worked the first time. When I tried to change the variables, it does not automatically send the email, unless I run the script again, it would then update the response sheet and then clears the checkbox. Please help me with this. Kindly see my code below.
function EmailNotification(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Course_AutoEmail'); //source sheet
var columnb = sheet.getRange('I:I'); //Column with check boxes
var columnbvalue = columnb.getValues();
var notifysheet = ss.getSheetByName('Responses'); //destination sheet
var data = [];
var rownum = [];
//Condition check in B:B (or check box column); If true copy the same row to data array
for (let i = 0; i < columnbvalue.length; i++) {
if (columnbvalue[i][0] === true) {
var columnb2 = sheet.getRange('I747:I'); //row started in row 747
columnb2.setValue('false');
data.push.apply(data, sheet.getRange(i + 1, 1, 1, 20).getValues());
//Copy matched ROW numbers to rownum
rownum.push(i);
//Copy data array to destination sheet
notifysheet.getRange(notifysheet.getLastRow() + 1, 1, data.length, data[0].length).setValues(data);
var activeRow = notifysheet.getLastRow();
var name = notifysheet.getRange(activeRow, 1).getDisplayValue(); // The number is the column number in the destination "responses" sheet that you want to include in the email
var employeeID = notifysheet.getRange(activeRow, 2).getDisplayValue();
var position = notifysheet.getRange(activeRow, 3).getDisplayValue();
var team = notifysheet.getRange(activeRow, 4).getDisplayValue();
var date = notifysheet.getRange(activeRow, 10).getDisplayValue();
var rec1 = notifysheet.getRange(activeRow, 19).getDisplayValue();
var rec2 = notifysheet.getRange(activeRow, 20).getDisplayValue();
var email = rec1 + "," + rec2;
var subject = name + ': 201 Completion';
//Body of the email message, using HTML and the variables from above
var message =
'<br><div style="margin-left:10px;">Hi, </div>' +
'<br><div style="margin-left:10px;">Good day!</div>' +
'<br><div style="margin-left:10px;"><b>' + name + '</b> has completed the course. </div>' +
'<br><div style="margin-left:20px;"><h3 style="text-decoration: underline; color: #f36f21">Employee Details: </h3></div>' +
'<div style="margin-left:25px;">Name: <b>' +
name +
'</b></div>' +
'<div style="margin-left:25px;">Position: <b>' +
position +
'</b></div>' +
'<div style="margin-left:25px;">Team: <b>' +
team +
'</b></div>' +
'<div style="margin-left:25px;">Completion Date: <b>' +
date +
'</b></div>' +
'<br><br><div style="margin-left:10px;">Let me know if you have any questions. </div>' +
'<br><div style="margin-left:10px;">Thanks! </div>';
MailApp.sendEmail(email, subject, '', {
htmlBody: message,
name: 'Updates',
});
}
}
}
I read your code.
if you don't want your checked checkbox unchecked in spreadsheet.
so you have to remove `columnb2.setValue('false');` line of code.
this line is made checkbox unchecked.
solution of other problems : http://one7techlab.com

Nothing similar and a not-so-frequent Apps Script question

Through trial and error I modified the below line of code to print the range B4:I59. Can someone help me to understand what the code says and/or how do I read it?
Original code
var printRange = '&c1=0' + '&r1=0' + '&c2=7' + '&r2='+row2; // B2:APn
Modified Code
var printRange = '&c1=1' + '&r1=2' + '&c2=9' + '&r2='+row2; // B4:I59
This is my whole code:
//* Print Extentions
function printPdf() {
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var gid = sheet.getSheetId();
var pdfOpts = '&size=A4&fzr=false&landscape=false&fith=true&gridlines=false&printtitle=false&sheetnames=false&pagenum=UNDEFINED&attachment=false&gid='+gid;
var row2 = 59;
var printRange = '&c1=1' + '&r1=2' + '&c2=9' + '&r2='+row2; // B4:I59
var url = ss.getUrl().replace(/edit$/, '') + 'export?format=pdf' + pdfOpts + printRange;
var app = UiApp.createApplication().setWidth(200).setHeight(50);
app.setTitle('Print Extentions List');
var link = app.createAnchor('Download PDF', url).setTarget('_new');
app.add(link);
ss.show(app);
}
The code works
In the line:
var url = ss.getUrl().replace(/edit$/, '') + 'export?format=pdf' + pdfOpts + printRange;
You are defining a URL that will allow you to export the given spreadsheet as a PDF using the specified options. The & symbols separate arguments you are passing into the URL.
This document gives a nice description of the parameters you are using. According to that document:
//r1=Start Row number - 1 row 1 would be 0 , row 15 wold be 14
//c1=Start Column number - 1 column 1 would be 0, column 8 would be 7
//r2=End Row number
//c2=End Column number

'setValue' errs, but only sometimes?

I'm trying to fetch stock prices from the web and save them automatically every five minutes or so. I've succeeded with the importXML() and the Google Sheets triggers but I do encounter ERRORS quite often. The problems seem to rise when saving the values from the imported cells to a new column at the end of the spreadsheet. Sometimes it all works fine, but sometimes some cells get an error and sometimes I get ERROR in all the cells.
This is the Google script I'm using:
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var queryString = Math.random();
for (var i=2; i <= 14; i++) {
var cell = '=IMPORTXML("' + 'http://www.netfonds.no/quotes/ppaper.php?paper=' + sheet.getRange('B' + i + '').getValue() + '.ST&' + queryString + '","' + sheet.getRange('A' + i + '').getValue() + '")';
sheet.getRange('C' + i + '').setValue(cell);
}
var datarange = sheet.getDataRange();
var numColumns = datarange.getNumColumns();
var nextColumn = numColumns + 1;
sheet.getRange(1, nextColumn).setValue(new Date());
SpreadsheetApp.flush();
sheet.getRange(2, numColumns + 1, 13, 1).setValues(sheet.getRange(2, 4, 13, 1).getValues());
}
And here is the spreadsheet.
In this Question I found out that adding a Browser.msgBox("hey!") and a clear() could help. But it still gives me errors trying it out unfortunately.