Setting a trigger on a programmatically created Google spreadsheet - google-apps-script

I am building a Google sheets platform where I make a new spreadsheet for a new user by copying a template spreadsheet. Because of a potential large amount of users, I need to be able to do this programmatically.
Part of the template is an onEdit trigger. So far I have not found a way to copy this trigger to the new spreadsheet. I have tried by using ScriptApp.newTrigger as shown below:
var newss = playertemplate.copy(playerid + '. ' + playername).getId()
var newsheet = SpreadsheetApp.openById(newss).getSheetByName('Sheet1')
var newfile = DriveApp.getFileById(newss)
newfile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.EDIT)
ScriptApp.newTrigger("submitBets").forSpreadsheet(newss).onEdit().create()
But the result is that the new trigger is created both on the "master" spreadsheet from which the above script is run, and on the new spreadsheet. I have found that this works for up to 20 new users, after which I run into the limit of the number of bound triggers on the master spreadsheet. When I remove the trigger on the master spreadsheet, it is removed on the new one as well.
I have found some old similar questions but none of them were solved, so I'm hoping a solution was developed in the past few years or someone found a workaround in the meantime.

Related

Google sheets macro only working when I manually trigger it

I have a spreadsheet that is connected a Hubspot workflow. When a deal is closed in our CRM, Hubspot creates a new row on the sheet with 3 pieces of data from the deal. Due to Hubspot's recommended best practices for working with Google Sheets integration, I have another sheet where I reference data from the sheet that receives the data. The problem arose when I realized that the reference sheet would not automatically refresh when new data was written to the synced sheet. So, I created a macro that copies the formula down using the fill handle every 5 minutes. This rescans the synced sheet and writes any new data to the reference sheet. This morning I woke up and there was some new data that should have been copied over to the reference sheet -- however it wasn't. I checked that the macro is running every 5 minutes, and it is. For the hell of it, I went to the menu and manually ran the macro and, to my surprise, it actually worked! I want this to be fully automated though and don't want to have to manually run a macro everytime I want the data to get copied over.
Data gets synced here
Data is referenced here
Macro Code:
/** #OnlyCurrentDoc */
function RefreshData() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A75').activate();
spreadsheet.getActiveRange().autoFill(spreadsheet.getRange('A75:A223'), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
spreadsheet.getRange('B75').activate();
spreadsheet.getActiveRange().autoFill(spreadsheet.getRange('B75:B234'), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
spreadsheet.getRange('C75').activate();
spreadsheet.getActiveRange().autoFill(spreadsheet.getRange('C75:C232'), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
spreadsheet.getRange('C75:C232').activate();
};
The problem is that your macro, doesn't work in the time-driven triggers context. The following "macro" is able to be called by a time-driven trigger:
function RefreshDataByTimeDrivenTrigger() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A75:A223')
.setValue(spreadsheet.getRange('A75').getValue());
spreadsheet.getRange('B75:B234')
.setValue(spreadsheet.getRange('B75').getValue());
spreadsheet.getRange('C75:C232')
.setValue(spreadsheet.getRange('C75').getValue());
};
Note:
/** #OnlyCurrentDoc */ was not included in the above code because it applies to the whole project.
I'm intentional using setValue instead of setValues as the same value should be added to all the cells from the specified range.
There are some methods that only works in certain contexts, i.e. SpreadsheetApp.getUi() works then called from a custom menu, but doesn't work when called from a time-driven trigger. The same happens with Range.activate(). Unfortunately the macro recorder adds a lot of Range.activate() and Spreadsheet.getActiveRange() methods and it's not smart enough yet to optimize the recorded user actions by itself, so, in order to make your macro to work when it's called by a time-driven trigger you have to adapt your code:
Remove statements like spreadsheet.getRange('A75').activate();.
Modify statements like spreadsheet.getActiveRange() to use statements like spreadsheet.getRange('A75').
If you are also interested in making your "macro" faster, you might also would like to replace patterns like
spreadsheet.getRange('A75').activate();
spreadsheet.getActiveRange().autoFill(spreadsheet.getRange('A75:A223'), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
by equivalent code that make fewer calls to Google Apps Script methods.
Related
Google sheets macro won't run on trigger
Try it this way:
function RefreshData() {
var ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("SheetName");
sh.getRange('A75').autoFill(sh.getRange('A75:A223'), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
sh.getRange('B75').autoFill(sh.getRange('B75:B234'), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
sh.getRange('C75').autoFill(sh.getRange('C75:C232'), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
}

Google Scripts onEdit not recognising data being edited on a sheet during a sync from a mobile device

I have a Google sheet that is updated by a mobile app created on AppSheet.
I have a column of data that I need to keep a history of so wrote a script to copy the column to a fblank column in another sheet.
function readdailyChecks() {
var sheetFrom = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Todays Checks");
var sheetTo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("History");
// Copy from 5th column, all rows for one column
var valuesToCopy = sheetFrom.getRange("D2:D100").getValues()
//Paste to another sheet from first cell onwards
sheetTo.getRange(1,sheetTo.getLastColumn()+1,valuesToCopy.length,1).setValues(valuesToCopy);
}
I then wrote another script to do this task when the sheet was edited thinking the sync would edit the sheet data.
function onEdit(e) {
if(e);
readdailyChecks(e)
}
The idea being that the app would sync once the form was completed, update the sheet and trigger the onEdit code to do it's stuff.
The problem is that the sync changes the sheets data without editing it so the historical data is not created!
Is there an onSync code or a way that when the data changes the script can be triggered?
I work at AppSheet. When updates are made to Google sheets via the Google Sheets backend API, they do not fire the onEdit trigger. I'm not sure why exactly this is, but it is a limitation imposed by Google. So that is what you are observing.
The AppSheet documentation suggests that you try a timed trigger instead, polling for changes. https://appsheethelp.zendesk.com/hc/en-us/articles/206483017-Google-Drive
Not the greatest, but it does work. Some AppSheet users have reported success with the onChange trigger instead of the onEdit trigger. To me, this defies logic based on the documented meaning on an onChange trigger, but it appears to work for these users, so worth a shot.

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 do I convert this google script to work offline?

I am trying to automate data entry while roaming offline using my Chromebook.
I know that google drive is enabled offline and a standalone script in GAS should in theory do the trick but im not sure how to put the pieces together. So far I have the below code which works perfectly online (gets stuck in "running" offline) and I've got the GAS app installed. Any guidance would be greatly appreciated!
function onOpen() {
var ui = SpreadsheetApp.getUi();
// Or DocumentApp or FormApp.
ui.createMenu('Invoice/Receipt System')
// creates a menu item "Submit Order"
.addItem('Record Invoice', 'menuItem1')
.addToUi();
}
function menuItem1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var is = ss.getSpreadsheetByName("Template_Invoice");
var lastID = is.getRange("j6");
var nextID = is.getRange("j7");
var lastIDValue = lastID.getValue();
var source = ss.getSpreadsheetByName("Key_Invoice");
// sets the 'Key_DailyInput' Sheet as source
var target = ss.geSpreadsheetByName("DataBase_Invoice");
// sets 'Key_DailyInput' sheet as the target for copying data to.
var sourceData = source.getSheetValues(5,1,source.getLastRow(),15);
// sets range to gather source 'Key_DailyInput' data by finding last row, and Line 5 to Column 15
target.getRange(target.getLastRow()+1, 1, sourceData.length,15).setValues(sourceData);
// finds last row of target 'Orders' and writes to +1 row past last row up to column 15 using setValues of sourceData
// Following simply clears DailyInput so new data can be entered
is.getRange('C5:c8').clearContent();
is.getRange('G7:G8').clearContent();
is.getRange('B12:h28').clearContent();
is.getRange('b31:b34').clearContent();
// increases value by +1 so next Sales Order ID is incremented by 1
var cell = is.getRange("j6");
var cellValue = cell.getValue();
cell.setValue(cellValue + 1);
nextID.setValue(lastIDValue + 1);
}
As stated in other responses, the answer appears to be 'No'. However, while researching I did find the Command Line Interface for Apps Script (clasp) to manage and edit your projects offline. I'll post it here hoping it will be helpful to Apps Script developers.
CLASP Features
Develop Locally. clasp lets you write code on your own computer and upload it to Apps Script via command line when you're done. You can also download existing Apps Script projects and then edit them locally. Once the code is local, you can use your favorite development tools like git to work on Apps Script projects.
* Manage Deployment Versions.
* Create, update, and view multiple deployments of your project.
* Structure Code. clasp automatically converts your flat project on script.google.com into folders.
You can find more information on clasp at https://developers.google.com/apps-script/guides/clasp. However, you'll also need to activate the Linux(beta) on your Chromebook utilizing these instructions.
Short answer
Google Apps Script can't be ran offline because they run on the server-side.
Explanation
From https://developers.google.com/apps-script/overview
Google Apps Script is a scripting language based on JavaScript that
lets you do new and cool things with Google Apps like Docs, Sheets,
and Forms. There's nothing to install — we give you a code editor
right in your browser, and your scripts run on Google's servers.

Unable to access (an save) my SpreadSheet Google App 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();
}
}