Unable to access (an save) my SpreadSheet Google App Script - google-apps-script

I have a Google SpreadSheet (filled through a form) associated to a Google Apps Script.
Now, the spreadsheet contains too many cells and I'm not able to load it anymore (server timeout).
I'm not interested in the data, but I really want to retrieve the script (the source code).
Unfortunately, the only way I know is to load the SpreadSheet first :-(
(Copying the Document ends in a timeout and the script is not copied.)
Any suggestion?
Regards,
RĂ©mi.

Create another script which makes a copy of original spreadsheet to backup the data and then clear the original spreadsheet through the script.
However this seems an issue which should be reported to Google Spreadsheet Forum
Here is an example code which will backup the spreadsheet as a copy and clear the original spreadsheet
function backupDataAndClear(){
var sourceSS = SpreadsheetApp.openById('ID_OF_ORIGINAL_SS');
var newSS = sourceSS.copy('Backup SS');
var sourceSheets = sourceSS.getSheets();
for(var i in sourceSheets){
sourceSheets[i].clear();
}
}

Related

Exception when openById of Spreadsheet in Google App

I implemented a Google Slide Add On which makes a copy of a linked spreadsheets and then opens it (to retrieve all charts in this sheet).
This is the code in question:
// id is the spreadsheet id
var sheetFile = DriveApp.getFileById(id);
var copy = sheetFile.makeCopy(sheetFile.getName() +'_'+ 'Copy');
Utilities.sleep(200);
// exception happens here
var sheet = SpreadsheetApp.openById(copy.getId());
Unfortunately this results for some sheets in the following error:
Exception: Service Spreadsheets failed while accessing document with id *************.
So I tried to find out why some spreadsheets work and some not and it lookls like that it does not work for not converted spreadsheets from excel. So I tested it by converting one of those excel sheets into a Google Sheet by Menu->File->Convert to Google Sheet.
This did not work... So I played around by replicated the Google Slide with the charts and I found out that I was not able to import the chart to a google slide from this converted spreadsheet. Even if I just create a new chart in this sheet everytime I go to the Slide App and try to insert the chart from this spreadsheet, no charts were displayed in the selection window.
It looks like that something went wrong when converting the excel to Google Sheets, I tried to do the conversion step multiple times... but no change.
[Edit]
I also tried to disabling V8 support.
[Edit2]
so for some reason I can now use SpreadsheetApp.openById(copy.getId()); when the spreadsheet was converted to google sheet. But as I mentioned before, it is still not possible to add any charts manually from this Google Sheet to presentation...
The error message Service Spreadsheets failed while accessing document with id ID you are receiving might in fact be related to this known issue on Google's side.
I suggest you star the issue here as all the updates regarding this will be posted there.
If it's a glitch I'd try to chain the commands this way:
var sheetFile = DriveApp.getFileById(id);
var copy_name = sheetFile.getName() +'_'+ 'Copy';
var sheet = SpreadsheetApp.openById(sheetFile.makeCopy(copy_name).getId());
This way the command openById won't fire before the file will be copied.

Google Sheets - Replace sheet without breaking references to that sheet

We are building a google sheets database where each user has their own spreadsheet that accesses a central sheet for information using apps script.
This means that with 50 employees, we have 50 spreadsheets to maintain. I am trying to find a way to push updates to all 50 spreadsheets without having to update each one manually. I have all the apps script code in a library that each user's sheet references, so I have the coding maintenance figured out. But keeping each users actual spreadsheet up to date with the latest features is proving difficult.
One way I'm figuring to do that is have a "Template" user sheet that gets updated with the changes/new features. Then when each user opens their spreadsheet, it cross references all of its sheets to the template sheet, and checks if it needs to replace it's sheet with the latest sheet based on time that it was updated in the template sheet. For example, when the sheet "Project Report" in the template is newer than the "Project Report" sheet in the user's spreadsheet, the user SS deletes it's current "Project Report" and copies the template "Project Report" sheet to it's own via the copyTo() method.
I have this all working with apps script, but the issue now is that when the user's local sheet is deleted and replaced with the new updated seet, all formula references to that sheet in other sheets break and replace the reference with #REF. I had planned on overcoming this by using only Named Ranges, but even the named ranges break when the sheet is replaced to the point where even the apps script can no longer find the named range because the named range it is looking for was automatically renamed when the new version of the sheet was imported (aka, "CustomNamedRange" in the template SS was renamed to "'SheetName'!CustomNamedRange" in the user SS).
The only way I know to overcome this issue at this point is to create a centralized "Range Index" spreadsheet that has all the named ranges with their destination sheet and range. I would have to create a custom function that filters through the range index and finds the address it needs based on the name given. For example, instead of calling "CustomNamedRange" in a sheet formula, I would call custom function: getNamedRange("CustomNamedRange"), and apps script would return the range found in the range index. And when a sheet is replaced with the newer version, no references would break because all references go through the apps script filter function.
The only problem with this is that I can foresee this method (calling every range needed in the script through a custom function) slowing down my spreadsheet A LOT because every time a range is called for, it will have to go search through the range index to find it and return it.
Does anyone have any other ideas on how to accomplish what I'm looking for? As in keeping 50+ individual spreadsheets updated with new features without having to do it manually and without breaking all the references?
Sorry for the long post, but I appreciate any ideas!
I had a similar problem and was able to resolve it by using SheetAPI to replace text. I have a template called Sheet1_Template and its hidden. I delete Sheet1, copy Sheet1_Template, show it and then replace all occurances of "Sheet1" in formulas to "Sheet1". Sheet API has to be enabled in the Resources and Google API Console.
function copyTemplate() {
try {
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spread.getSheetByName("Sheet1");
if( sheet !== null ) spread.deleteSheet(sheet);
sheet = spread.getSheetByName("Sheet1_Template");
sheet = sheet.copyTo(spread);
sheet.setName("Sheet1");
sheet.showSheet();
sheet.activate();
spread.moveActiveSheet(0);
var requests = {"requests":[{"findReplace":{"allSheets":true,"find":"Sheet1","replacement":"Sheet1","includeFormulas":true}}]};
Sheets.Spreadsheets.batchUpdate(requests, spread.getId());
}
catch(err) {
Logger.log("error in copyTemplate: "+err);
}
}
I haven't been able to test implementation of it yet, but I believe the answer above is what I was originally looking for.
I haven't spent any time messing with the API yet, so in the meantime I have found another solution:
Google Sheets recently added macros to it's feature set. The beauty of this is that You can see and edit the macro code after you've recorded your actions in the sheet. For now, I plan on recording a macro when I make updates to the template sheet, then copying the script for that macro into a custom function in my library that will run every time a user opens their spreadsheet. When they open their SS, apps script will check to see if the library's macro function has a later date than the last time the sheet was opened. If it does have a new date, then it will run the macro script, and that user's SS should get updated to the same state as the template.
Also if you are seeing that you cannot run the query from #TheWizEd
It may be due to "Sheets API" not being enabled at Advanced Google services. Please enable>
In the script editor, select Resources > Advanced Google services In the dialog that appears, click the on/off switch for Google Sheets API v4. Please turn on. Click OK button.
Thank you so much to TheWizEd for getting me started (please vote for that post too).
This is what I needed:
function replaceFormulasInSheet(sheet, searchFor, replaceWith) {
// https://stackoverflow.com/a/67151030/470749
// First you need to do this to enable the feature: https://developers.google.com/apps-script/guides/services/advanced#enabling_advanced_services
// https://developers.google.com/sheets/api/quickstart/apps-script
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#findreplacerequest
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/batchUpdate
const spread = SpreadsheetApp.getActiveSpreadsheet();
const requests = {
"requests": [
{
"findReplace": {
// "allSheets": true, Omitting this property and instead setting the sheetId property is the only way to effectively set allSheets as false.
"sheetId": sheet.getSheetId(),
"find": searchFor,
"replacement": replaceWith,
"includeFormulas": true
}
}
]
};
return Sheets.Spreadsheets.batchUpdate(requests, spread.getId());
}
Also note that it does not work for sheets with hyphens in their names. If you need hyphens in their names, remove the hyphens beforehand and re-add them after.

Wishing to run calendar import script on specific sheet not on active sheet

I would like the Google Calendar import script run on a specific sheet. Lets Say "Sheet4" The script works well on any current active sheet but I seem to be unable to modify all the proper lines in the script to make it work properly to be directed to a specified sheet.
Here is a link to the sheet
https://docs.google.com/spreadsheets/d/1DI_gnXyeKrR_t_6u0-EKzfUjeMmXj8GC6HlU-3uGmkc/edit#gid=2105065853
I tried to paste the code but kept getting formatting error. Apologies in advance. I am very new to this
You haven't shared the Google Spreadsheet but you can use the below code snippet to perform task on a particular sheet.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet4");
For sheet of different spreadsheet.
var sheet = SpreadsheetApp.openById("<<ENTER SPREADSHEET ID>>").getSheetByName("Sheet4")

Google Sheets script, copyto and replace existing sheet

I've been searching for the past few weeks and haven't been able to figure out this script. What I'm trying to do is figure out a way for me to duplicate a pictorial calendar on a master Google Sheets file to another Google Sheets file that I manage. Every time there's an update on the master calendar, I'd love for it to automatically update in the other Google Sheets file that I manage. Right now I have to copy paste everything, reformat, and reimport images. I did find a script that somewhat works, but it has some issues that cause it to be just as much work.
The script is a copyTo script, it allows me to copy a sheet titled "Pictorial Calendar" from the master Google Sheets file (called "Master Calendar") to a different Google Sheets file (called "My Calendar"). I even set up a trigger that allows the script to run whenever I make an edit.
However, it keeps creating new sheets titled "Copy of Pictorial Calendar 1" "Copy of Pictorial Calendar 2" etc.) and I can't figure out how to make the script replace the existing sheet instead of creating new sheets.
I also would love to be able to change the duplicated sheet to just be called "Pictorial Calendar" in the "My Calendar" file. The script I'm using is:
function copyMasterCalendar() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[2];
var destination = SpreadsheetApp.openById("1exiUWVypFpYeHMkXHO3sMUTGupiC2gQjZIF0Ss44-pU");
sheet.copyTo(destination);
}
Any and all help would be much appreciated! Thank you!
If I understood you correctly try this...
function copyMasterCalendar() {
var source = SpreadsheetApp.getActiveSpreadsheet(),
sheet = source.getSheetByName('Pictorial Calendar'),
destination = SpreadsheetApp.openById("1exiUWVypFpYeHMkXHO3sMUTGupiC2gQjZIF0Ss44-pU"),
destSheet = destination.getSheetByName('Pictorial Calendar'),
copydSheet = sheet.copyTo(destination);
copydSheet.getDataRange().copyTo(destSheet.getDataRange());
destination.deleteSheet(copydSheet);
}

How to access data on different Google Spreadsheet through Google Apps Script?

I'm writing a Google Apps Script on my Google Site and am trying to use data that is provides on 2 different tabs in a Google Spreadsheet. From what I thought I understood from the documentation I could use all available methods in the SpreadsheetApp class on a Sites script by just using the openById() method.
Anyway here is what I tried to do
function doGet(e) {
var doc = SpreadsheetApp.openById(SPREADSHEET_ID_GOES_HERE).getActiveSheet();
SpreadsheetApp.setActiveSheet(doc.getSheetId()[1]);
//....
}
I get the error
Cannot find method setActiveSheet(. (line 4)
I'm pulling my work off this link: Storing Data in Google Spreadsheets and also the Ui Service section listed under Building User Interfaces.
Anybody seeing what I'm doing wrong in these two lines?
setActiveSheet should be used only with the spreadsheet displayed by the UI, a sheet in a spreadsheet you have opened in your browser.
With SpreadsheetApp.openById you are opening a spreadsheet to access its data, but it doesn't open in your browser. It hasn't an UI.
I found this comments in https://developers.google.com/apps-script/class_spreadsheetapp?hl=es-ES#openById :
// The code below opens a spreadsheet using it's ID and gets the name for it.
// Note that the spreadsheet is NOT physically opened on the client side.
// It is opened on the server only (for modification by the script).
var ss = SpreadsheetApp.openById("abc1234567");
Some examples assume your script is running into your spreadsheet. It's not your case, because you are running a script as a service, which should have its own User Interface.
I think #megabyte1024 addresses the syntax errors, but in answer to your comment to #YoArgentina:
Do you happen to know of a way to access data on different tabs then
through a service not running inside the Spreadsheet?
Does this sort of help?
var ss = SpreadsheetApp.openById(SPREADSHEET_ID_GOES_HERE);
var sheets = ss.getSheets();
// the variable sheets is an array of Sheet objects
var sheet1A1 = sheets[0].getRange('A1').getValue();
var sheet2A1 = sheets[1].getRange('A1').getValue();
You need to access each sheet separately.
var ss = SpreadsheetApp.openById(SPREADSHEET_ID_GOES_HERE);
var sheet = ss.getSheets()[0]; // "access data on different tabs"
ss.setActiveSheet(sheet);
There is at least one problem in these two lines. The 1st one is that the setActiveSheet method parameters is a Sheet class object and the getSheetId method returns an integer value. By the way this method (getSheetId) is not documented. The 2nd problem can happen if the SpreadsheetApp has no active spreadsheet. In this case there is the "Please select an active spreadsheet first." error. Use the SpreadsheetApp.setActiveSpreadsheet method to set an active spreadsheet.