Noob problem, and noob question. I've got 4 eyes, and none work, because I can't see where the problem is...
I'm starting on building a mileage logging app in google sheets. An important part of this is putting the correct information in the correct cell. I've got the start of a script, and I'm already running into problems. My log sheet (named 'Mileage Log') has 1 row of headers. The data starts on row 2. When I run my script, it gives me lastRow = 4. Why?
Here's what I'm using:
// Get the 'Mileage Log' spreadsheet and sheet
var logSpreadsheet = SpreadsheetApp.openById('1PR3pK55urtYY9mnJTb_1Iacys0tj2lGd88CEfrhBIjs');
var logSht = logSpreadsheet.getSheets()[0];
// Determine the last used row in the "Mileage Log" spreadsheet
var lastRowLogSht = logSht.getLastRow();
Logger.log("The value of 'lastRowLogSht' is: " + lastRowLogSht);
}
(Apologies if this did not post over properly)
Does anybody have any idea what's going on and how to fix it?
Related
I have a Google Sheets script that I've been using for the past 2+ years that grabs a chunk of data and transcribes it into a pair of tally sheets, then clears the cells that had been filled creating said chunk of data so the process can be started over. This is used for an inventory calculation system. The script has reliably worked up until roughly 3 weeks ago, but I now encounter an edit protection error when users with limited access to the sheet attempt to run the script. None of the editable cells/ranges reference in the script are locked to any user, but the sheet does have protection on cells I do not want anybody to make inadvertent changes to.
The script is:
function CopyErADD() {
var sss=SpreadsheetApp.getActiveSpreadsheet();
var sheet = sss.getSheetByName('ADDER'); //Entry Sheet
var rangeIn = sheet.getRange('B32:N45'); //Range to copy into "Incoming" sheet
var dataIn = rangeIn.getValues();
var ts = sss.getSheetByName('Incoming'); //Tally sheet in
ts.getRange(ts.getLastRow()+1, 1, dataIn.length, dataIn[0].length).setValues(dataIn);
var rangeOut = sheet.getRange('B48:O54'); //Range to copy into "Outgoing" sheet
var dataOut = rangeOut.getValues();
var tss = sss.getSheetByName('Outgoing'); //Tally sheet out
tss.getRange(tss.getLastRow()+1, 1, dataOut.length, dataOut[0].length).setValues(dataOut);
SpreadsheetApp.flush() // NEWLY ADDED PER METAMAN'S SUGGESTION
sheet.getRange('E2:E5').clearContent();
sheet.getRange('B7:B20').clearContent();
sheet.getRange('E7:H20').clearContent();
sheet.getRange('I7:I20').setValue('kg');
sheet.getRange('L7:L20').clearContent();
sheet.getRange('B24:B29').clearContent();
sheet.getRange('J24:J29').clearContent();
}
I also have an "erase only" script that runs the second second part of the script only (if data has been entered incorrectly) that executes perfectly fine. It is only when coupled with the copy/transcribe portion of the script that the protection error occurs.
function ErADD() {
var sss=SpreadsheetApp.getActiveSpreadsheet();
var sheet = sss.getSheetByName('ADDER');
sheet.getRange('E2:E5').clearContent();
sheet.getRange('B7:B20').clearContent();
sheet.getRange('E7:H20').clearContent();
sheet.getRange('I7:I20').setValue('kg');
sheet.getRange('L7:L20').clearContent();
sheet.getRange('B24:B29').clearContent();
sheet.getRange('J24:J29').clearContent();
}
Commenting out the sheet.getRange.... etc clearContent and setValue portion of the first script allows it to complete successfully, so I attempted to create a master function that calls the CopyErAdd script (sans clear portion) and then calls the ErADD script, and I encounter the same error. Both script can be run on their own successfully, but when combined the erase portion encounters the error.
Does anybody see any issues that I am missing, or did something occur over the past few weeks that I'm not aware of that could cause this protection error?
I appreciate any ideas anybody might have.
Edit - Thank you MetaMan for the tips for making the script more efficient.
As for the protection, "Incoming" and "Outgoing" copy destination sheets are completely open, no protection at all. "ADDER" sheet is protected except certain cells that are edited by user, and are referenced in the script.
E2:E5 (actually E2:I5 open, since the macro button sits on top of the F2:I5 range), B7:B20, E7:I20, L7:L20, B24:B29, J24:J29, All unprotected.
Adding the line
SpreadsheetApp.flush()
in between the copy section and clearing section of the code worked (as shown in the updated code snippet). I'm no longer encountering a range protection error.
I really appreciate the fix, but I'm boggled over why I've never needed that line until recently. I guess you don't need flush() until you do.
You could replace this:
sheet.getRange('I7').setValue('kg');
sheet.getRange('I8').setValue('kg');
sheet.getRange('I9').setValue('kg');
sheet.getRange('I10').setValue('kg');
sheet.getRange('I11').setValue('kg');
sheet.getRange('I12').setValue('kg');
sheet.getRange('I13').setValue('kg');
sheet.getRange('I14').setValue('kg');
sheet.getRange('I15').setValue('kg');
sheet.getRange('I16').setValue('kg');
sheet.getRange('I17').setValue('kg');
sheet.getRange('I18').setValue('kg');
sheet.getRange('I19').setValue('kg');
sheet.getRange('I20').setValue('kg');
with this:
sheet.getRange('I7:I20).setValue('kg');
also replace this:
var ss = sss.getSheetByName('ADDER'); //Entry sheet
var sheet = SpreadsheetApp.getActive().getSheetByName('ADDER');
with this:
var sheet = sss.getSheetByName('ADDER);
If you are doing anything immediate after this function with the data then you might wish to add SpreadsheetApp.flush()
I can't comment on the protection since none of that information was provided.
This may be a simple issue, but I am having some trouble with a section of code.
Here is the code:
function CreateSheet() {
function toTitleCase(str) {
return str.replace(/\w\S*/g, function (txt) {
return txt.charAt(0)
.toUpperCase() + txt.substr(1)
.toLowerCase();
});
}
var ss = SpreadsheetApp.getActive();
var templatesheet = ss.getSheetByName('Template');
//var fieldName = Browser.inputBox('Field Name', 'Insert Field Name', Browser.Buttons.OK_CANCEL);
var ui = SpreadsheetApp.getUi();
var fieldResult =
ui.prompt(
'FIELD NAME',
'Please type in the Field Name',
ui.ButtonSet.OK
)
var fieldName = toTitleCase(fieldResult.getResponseText());
var acreResult = ui.prompt('ACRES',
'Please type in the # of acres, if the # is not known just leave it blank',
ui.ButtonSet.OK
)
var acres = acreResult.getResponseText();
var url = '';
ss.insertSheet(fieldName,3,{template: templatesheet});
ss.getRange('B3:D3').activate();
ss.getCurrentCell().setValue(fieldName);
ss.getRange('E3').activate();
ss.getCurrentCell().setValue(acres);
url += '#gid=';
url += ss.getSheetId();
ss.setActiveSheet(ss.getSheetByName('Summary'));
SpreadsheetApp.setActiveSpreadsheet(ss);
ss.getRange('A5:J5').activate();
ss.getRange('A5:J5').insertCells(SpreadsheetApp.Dimension.ROWS);
The last line is where it is throwing the exception message:
Service Spreadsheets failed while accessing document with id..
If I go into the sheet itself and manually insert range 'A5:J5' then run the code it will work. What am I missing here?
Service Spreadsheets failed while accessing document with id
is usually an error message one obtains when hitting the maximum size limit for a spreadsheet
This limit is 5 000 000 cells, so it should not be the issue for your spreadsheet
However, several users experienced the same problem as you and have reported it on Google's Public Issue Tracker here or here
It is likely to be a bug and it currently being investigated by Google
Some users reported that they experience the problem only with V8 runtime
Try to disable it (Run > Disable new Apps Script runtime powered by V8), hopefully it will solve the issue temporarily
Otherwise, try to find a workaround replacing the line leading to the error
When I reproduce your script it does not error for me, this is why I can only give you some suggestions
If insertCells gives you trouble, try insertRowAfter() or similar instead
If the problem comes from ss.getRange('A5:J5'), try ss.getActiveSheet().getRange('A5:J5') or ss.getSheetByName('Summary').getRange('A5:J5')
Also, try removing the line SpreadsheetApp.setActiveSpreadsheet(ss); - you already defined ss as the active spreadsheet above, there is no need to set it to active again
I had this same problem related to insertCells. It drove me nuts for a couple of days but I finally just solved it! In case this helps someone else, here is a link to my answer as well as a copy/paste of it to be thorough.
This was a REALLY confusing issue to solve, as the errors reported by
the debugger did not point to the true culprit.
In another cell elsewhere on the sheet, I had this formula:
=SUMPRODUCT(LEN($A$5:$A)>0)
But since my inserted cells started with A5, this was causing the
error to be thrown when I would attempt the insert, if it tried to
insert ahead of A5. By removing this formula, the insert code works
perfectly every time, immediately.
So if you get this error and it is not related to having a sheet that
is too large etc., check to see if you have another formula somewhere
that is referencing the cell being inserted on.
Sometimes this error is caused by a process or calculation that was triggered by an earlier part of the script that has not completed by the time you try to insert those cells.
For example, if you have a formula that is summing a column in your summary sheet, that formula may still be calculating at the time you are trying to shift the rows that the sum formula is referencing. You can force the order of operations to complete those calculations before shifting the rows by adding SpreadsheetApp.flush(); before you insert new cells.
SpreadsheetApp.setActiveSpreadsheet(ss);
SpreadsheetApp.flush();
ss.getRange('A5:J5').activate();
ss.getRange('A5:J5').insertCells(SpreadsheetApp.Dimension.ROWS);
I had same issue.
First, you always need to make sure the sheet you are working on is an actual 'Google SpreadSheet' and not an uploaded one (for example, .xlsx or .xls).
Then use the Save as function to save the document as a Spreadsheed; this solution worked for me.
I found that a chart using the range caused this exception, remove the chart and it worked.
I ran into the same error message, with a sheet of 400 rows and 9 columns only. Inspired by the variouos proposals for solutions, I tried the following, and this did the trick:
duplicated the "orig sheet" to "copy of sheet"
deleted rows 4 to [last row] in "orig sheet" (so only 3 rows left)
copied rows 4 to [last row] from "copy of sheeet" back to "orig sheet"
and the script worked fine again :-)
(advantage: I did not have to change any formulas or scripts)
I'm new to scripts as you can see, I need a script where in I can get a data on a table (Sheet 1!A1:E7 - which updates every hour as well) and copy it (as TEXT) to a new sheet (Sheet 2). I need Sheet 2 to generate new rows/columns with the every hour (24 hrs) for 7 days. I searched the whole net to find this, but to no avail though.
Hoping to find answers to this.
Surpised the internet didn't throw up anything to learn how to script, but will share the route I took with you.
Codeacademy. Great for learning the basic priciples of Javascript
Once you've done there, next stop should be here.
This is googles reference site for scripting. But also has a few have a go tutorials that give insight into Google Application scripts and how they work.
That should give you a great starting point to build your own scripts.
I'd also keep this link to hand, for great rerefences, W3Schools
Has javascript references and tutorials
You'll be on your way in no time at all, and once you hit brick walls, or code isn't behaving properly. There is good old HERE, StackOverflow to visit.
I don't understand what you mean in your question "Generate new columns"
because if the source table is always A1:E7 then you don't need extra columns on sheet 2. Only extra rows as new data is imported.
This is a quick solution to your question.
function tableCopy() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName("Sheet1");
var targetSheet = ss.getSheetByName("Sheet2");
var values = sourceSheet.getRange("A1:E7").getValues();
var valuesLength = values.length;
if (!valuesLength) return;
var lastRow = targetSheet.getLastRow();
var requiredRows = lastRow + valuesLength - targetSheet.getMaxRows();
if (requiredRows > 0) targetSheet.insertRowsAfter(lastRow, requiredRows);
targetSheet.getRange(lastRow + 1, 1, valuesLength, values[0].length).setValues(values);
}
to get it working as a timer, you will have to add a time driven trigger to the function. To trigger it at the times you require.
I hope this helps
I am new to Google scripting, so I apologize if this is a naive question. I do not know how to get a variable reference to a sheet within a spreadsheet that is not the first sheet.
In my spreadsheet, I have two sheets, Agenda and Info. Agenda is the first sheet(index 0) and Info is the second. I can get a reference to Agenda, but I cannot get a reference to Index. This is the code I have tried:
var info_sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Info');
info_sheet.getName() always comes out being Agenda, though. What do I do?
There are 2 ways to get access to a specific sheet in a spreadsheet : by its name as you were showing in your code or by its index like in the second example below.
Just run this test to see the results on a spreadsheet with at least 2 sheets (I changed the sheet names to the 'standard default values in US locale' to make the test working for anyone, re-set it to your parameters if needed)
function testSheetNames(){
var info_sheet_example1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2');
var info_sheet_example2 = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];
Logger.log('name method result = '+info_sheet_example1.getName());
Logger.log('index method result = '+info_sheet_example2.getName());
}
That said, your example should return the correct value, I'm not sure why it didn't in your tests.
I've created a Google spreadsheet with imported data on one cell, extracting specific string to another cell and pasting the data in a table with a trigger for every 2 hours.
Now everything works perfectly when running the script manually but when logged out and waiting for the cells to fill, sometimes the pasted cell getting "#N/A" value.
Here is the code I'm using:
function PasteV(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var timestamp= sheet.getRange("D1").getValue();
var sale= sheet.getRange("G1").getValue();
var rent= sheet.getRange("J1").getValue();
sheet.appendRow([timestamp, rent, sale]);
}
Again when running manually countless times - no problem.
I'll appreciate your help.
Thanks.
#N/A is caused by using a custom function. There is an issue for it on the google-apps-script issue tracker, see https://code.google.com/p/google-apps-script-issues/issues/detail?id=1131
Sounds like the same bug, your description sounds the same.