Google apps script not throwing exception - google-apps-script

I have been playing around google apps script for a while, and I stumbled across the "Your input contains more than the maximum of 50000 characters in a single cell" error. But when I tried to prevent my script from crashing because of it, using try-catch statement, it didn't work.
I checked in the Google apps script documentation site (https://developers.google.com/apps-script/), and found nothing.
Moreover, I tried to run that sample code:
function myFunction() {
try
{
var a = ""
for (i = 0; i< 50000; i++)
a += '111'
SpreadsheetApp.open(DriveApp.getFileById("FileID")).getActiveSheet().getRange(1,1).setValue(a)
}
catch (e)
{
Logger.log(e.message)
}
}
And it crashed, leaving no record in the log.
Any idea on how to prevent crashing? preferably with some code segment that will allow me to manipulate the input?
I will be grateful for any help.
EDIT
My script should handle big amounts of data, so running time is really important for me. Right now I'm using a solution that looks like
a.substring (0,50000)
But the thing that I really want to see is something that will be activated only when needed, so it will be faster...

To solve your issue of catching the "Your input contains more than the maximum of 50000 characters in a single cell" error use SpreadsheetApp.flush();
function myFunction() {
try
{
var a = ""
for (i = 0; i< 50000; i++)
a += '111'
SpreadsheetApp.open(DriveApp.getFileById("FileID")).getActiveSheet().getRange(1,1).setValue(a);
SpreadsheetApp.flush();
}
catch (e)
{
Logger.log(e.message)
}
}
Note: I am not answering the performance issue as I think that has been addressed in the previous answer.

How about something like:
var CELL_MAX_LEN = 50000; // Or whatever value you choose
function checkAndWriteCellValue(range, value) {
if (value.length > CELL_MAX_LEN) {
value = 'Too long!'; // Or something else, truncate value etc
}
range.setValue(value);
}
You could call it like this:
var range = spreadsheet.getActiveSheet().getRange(...); // Add the specifics of your range
checkAndWriteCellValue(range, value);

Related

App Script how to customize a non-error message in doGet()

[edited]
I have a doGet() function that searches for a specific timestamp from a Gsheet and update that row's status based on what the approver clicked in the email (i.e. approved or disapproved).
Searching and updating work perfectly but the custom message I want to convey to the Approver is a bit confusing because the tab shows "Error" and a reference to the code's line number. Please refer to screenshot below:
It might be because I'm using "throw" to show my custom message so I'd like to know the right way to show custom message. I've seen posts in try/catch but I couldn't understand how it is used for this case where there's actually no error.
Will appreciate any help. And apologies for this newbie question.
Snippet of my code is below:
function doGet(e) {
....
// now search again using the adjusted timestamp
for (var i = 0; i < data.length; ++i) {
var row = data[i][1].toString().indexOf(revisedtimestamp);
if (row > -1) { //found
var a = i;
sheet.getRange(a + 1, approvalCol).setValue(e.parameter.approval);
throw ("Your decision has been sent to the requestor cc: Finance for processing");
break;
} else { //not found
throw ("There is a problem locating this request. Finance is automatically notified to look into this.");
}
}
Today I found a reference for web apps using HtmlService.createHtmlOutput or ContentService.createTextOutput for this purpose. So I replaced throw with these lines:
var HTMLString = "<style> h1,p {font-family: 'Helvetica', 'Arial'}</style>"
+ "<h1>Approval process completed.<br>"
+ UImsgForApprover + "</h1><p>";
HTMLOutput = HtmlService.createHtmlOutput(HTMLString);
return HTMLOutput
My custom message shows nicely enough for my needs, as shown below.
ContentService.createTextOutput also works ok, it's just unformatted text.

If statement in for loop referencing incremented variable

as quite an novice when it comes to coding, I ran into this problem with my code:
I use Google App Script [Edit: Corrected Google App Engine to Google App Script] to go through a list of timestamps and filter for stamps that equal the current month. Therefor I load the spreadsheet, the according sheet and get the data from all the rows as an object.
In the next step I go though all the elements of the object and check whether they contain the current date.
/* Initial data */
var email = "name#domain.com";
var spreadsheet = SpreadsheetApp.openById("1bN7PTOa6PwryVvcGxzDxuNVkeZMRwYKAGFnQvxJ_0nU");
var tasklist = spreadsheet.getSheets()[0].getDataRange();
var tasks = tasklist.getValues();
var tasksnum = tasklist.getNumRows();
Logger.log(tasks[7][2]); //Console returns "01.12.2014"
Logger.log(tasks[7][2].indexOf(month)); //Console returns "12.2014"
/* Filter tasks by month */
for (var i = 1; i < 9; i++) {
if (tasks[i][2].indexOf(month) >= 0) {
Logger.log(tasks[i]);
}
else {
return;
}
}
What drives me crazy is the following: As stated above, the for loop doesn't work. But if I alter it like this
if (tasks[7][2].indexOf(month) >= o) {
it works like a charm. And that's what I don't get. i should be incremented til 9 so should be seven at some point. At least then, the condition should be true and the loop should return a log.
What am I missing?
Thank you all in advance.
ps: If I am just following the wrong path of how to implement the function, please let me know.
ps2: I think my question's title is a bit cryptic. If you have a better one in mind, I'd love to change it.
The reason your original code doesn't work is due to the return statement in your else block. Return exits the function immediately, so your loop never gets past the first "false" of your IF.
remove the "return" (or the else block entirely) and your code should work.
I'm not sure what's supposed to be in the month variable but I suggested building a string to match your date format and doing string comparisons instead of the indexOf() strategy you're trying. This code is tested and does just that:
function test() {
/* Initial data */
var spreadsheet = SpreadsheetApp.openById("");
var tasklist = spreadsheet.getSheets()[0].getDataRange();
var tasks = tasklist.getValues();
var tasksnum = tasklist.getNumRows();
/* Filter tasks by month */
var today = Utilities.formatDate(
new Date(),
spreadsheet.getSpreadsheetTimeZone(),
"dd.MM.yyyy"
);
for(var i=1; i<9; i++){
if (tasks[i][2] == today){
Logger.log(tasks[i]);
}
}
}

error - "Method Range.getValue is heavily used by the script"

I posted this question previously but did not tag it properly (and hence why I likely did not get an answer) so I thought I would give it another shot as I haven't been able to find the answer in the meantime.
The below script is giving me the message in the title. I have another function which is using the same getValue method but it is running fine. What can I change in my script to avoid this issue?
function trashOldFiles() {
var ffile = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B3:B3").getValue();
var files = DriveApp.getFilesByName(ffile);
while (files.hasNext()) {
var file = files.next();
var latestfile = DriveApp.getFileById(listLatestFile());
if(file.getId() ==! latestfile){
file.setTrashed(true);
}
}
};
Is it an error or an execution hint(the light bulb in the menu)?
are you using that method on other part of your code? probably in listLatestFile()?
I got the same execution hint by calling getRange().getValue() in listLatestFile() (using a loop)
and the hint always mentioned that the problem was when calling
var ffile = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B3:B3").getValue();
in the function trashOldFiles() even when the actual problem was in other function.
Check if you are calling it in other place in your code, probably inside a loop.
OK, so Gerardo's comment about loops started to get me thinking again. I checked some other posts about how to re-use a variable and decided to put the listLatestFile() value in my spreadsheet -
var id = result[0][1];
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B5:B5").setValue(id);
//Logger.log(id);
return id;
and then retrieved the latest file ID from the spreadsheet to use as a comparison value for the trashOldFiles() function which worked a treat.
function trashOldFiles() {
var tfile = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B3:B3").getValue();
var tfiles = DriveApp.getFilesByName(tfile);
var lfile = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B5:B5").getValue();
while (tfiles.hasNext()) {
var tfile = tfiles.next();
if(tfile.getId() !== lfile){
tfile.setTrashed(true);
}
}
};
Not sure if that approach was best practice but it did work for me. If anyone has suggestions for achieving this in a more elegant way, I'm all ears.

Taking single sheet Google spreadsheet, making it into a pdf and placing it in Drive

I've been hours at this trying every which way and any kind of function that might result in something and I'm getting nowhere and frustrated. The code (stripped to the bare essentials):
function alone() {
try {
spreadSheetFile = DocsList.getFileById("KEY FOR A GOOGLE SPREADSHEET").getAs('application/pdf');
}
catch (e) {
Logger.log ("Catched something: "+e+"\n"+e.stack);
}
createFile('test file', content, 'application/pdf');
}
Getting the dreaded "Unexpected exception upon serializing continuation" and not even going to the catch, so nothing logged. I've used various methods tagged onto the end of "getAs", getBlob(), just about everything. I'm guessing this is just another part of Google code that's nogga, nogga, noggonna work here anymore.
your syntax is simply wrong...
try like this and it will work : (the sheet in this example has a single cell with value "empty sheet" and is shared)
function alone() {
try {
var spreadSheetFile = DocsList.getFileById("0AjUO-g3TOXkodHNtUUxwMEY5UHNCaTE3TDZLSmgweWc")
var pdf = spreadSheetFile.getAs('application/pdf');
} catch (e) {
Logger.log ("Catched something: "+e+"\n"+e.stack);
}
DocsList.createFile(pdf)
}

Google Script - Simple function not doing anything

I made a function nearly identical to this and it worked great. This one tells me it is running but nothing actually happens in my inbox. I get no errors, either.
(This is my first day working with Google scripting so I'm sure it's a rookie mistake.)
function autoArchiveOldInboxItems() {
var search_term = "label:inbox older_than:30d";
while(GmailApp.search(search_term).length > 0){
var threads = GmailApp.search(search_term,0,100);
GmailApp.markThreadsRead(threads);
GmailApp.moveThreadsToArchive(threads);
}
}
I tried searching "in:inbox" as well as "label:inbox".
For some reason, this made it happy:
function kickOff(){
autoArchiveOldInboxItems();
}
function autoArchiveOldInboxItems() {
var search_term = "label:inbox older_than:30d";
while(GmailApp.search(search_term).length > 0){
var threads = GmailApp.search(search_term,0,100);
GmailApp.markThreadsRead(threads);
GmailApp.moveThreadsToArchive(threads);
}
}
Then, I call the kickoff function and it runs. Strangely, when I did it before, I was in the editor and chose to run that function and it kept doing nothing. Possible bug? Or maybe it's just me.
You should see my inbox now. :)