I have been trying to install an installable trigger for a googlesheet workspace addon when a button is clicked. The trigger is meant to get fired whenever a cell is modified.
Unfortunately when a cell is modified, the trigger keeps getting disabled. The "disabled reason" (in Apps Script > Triggers > Last run column in the list) says: This trigger has been disabled for an unknown reason. I have tried calling from onHomepage() also.
Here is the code:
function createWidgetDemoCard() {
return CardService
.newCardBuilder()
.setHeader(...)
.addSection(
CardService.newCardSection()
.setHeader('Simple widgets') // optional
.addWidget(CardService.newTextParagraph().setText('Some text'))
.addWidget(CardService.newImage().setImageUrl('.../trees-autumn-colors-lake-picutre-600w-1827312116.jpg'))
.addWidget(CardService.newButtonSet().addButton(CardService.newTextButton()
.setText('Create trigger')
.setTextButtonStyle(CardService.TextButtonStyle.FILLED)
.setOnClickAction(CardService.newAction().setFunctionName('createSpreadsheetOpenTrigger'))
.setDisabled(false))))
.build();
}
function createSpreadsheetOpenTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('TestMe')
.forSpreadsheet(ss)
.onEdit() //onChange() not working`enter code here`
.create();
}
function TestMe(e) {
var range = e.range;
range.setNote('Last modified: ' + new Date());
}
The authscopes are:
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/spreadsheets"
]
The code from the TestMe() function works perfectly in a container-bound script. But because I am developing a Workspace addon, I want in a standalone script.
I can't really find a comprehensive documentation about developing an workspace addon.
Thanks!
Related
I am trying to solve the following case: I have a template that is copied by users and linked to a Google Form. Also, I have a script that does some configuration to the Form Responses tab for its further usage. It works perfectly in the template, however, the installable onFormSubmit() trigger is not copied together with the template. To solve this I added onOpen() trigger that installs the onFormSubmit() which was confirmed to work.
The issue I am facing is that while onFormSubmit() is successfully installed in the template copy, it still does not fire automatically. I assume that this is related to some permissions issue. Is there any way to rewrite the script to avoid additional authorization?
function onOpen(e) {
addFormSubmissionListener();
//// other init...
}
function addFormSubmissionListener() {
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("onFormSubmit")
.forSpreadsheet(sheet)
.onFormSubmit()
.create();
}
function onFormSubmit(e) {
var range = e.range
var sheet = range.getSheet();
var spreadsheet = SpreadsheetApp.getActive();
if(spreadsheet.getSheetByName('Responses') == null) {
sheet.setName('Responses');
sheet.insertColumnsAfter (7,10)
spreadsheet.getRange('Tech!A:J').copyTo(spreadsheet.getRange('Responses!H:O'), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
sheet.hideColumns(16, 2)
var curr_sheet = spreadsheet.getSheetByName('Jira import')
updateFormulasTwoRows(curr_sheet);
}
}
Answer:
If you create a new project you will always have to authorise it, there isn't really a way of getting around this.
how to get current list of sheet names automatically refresh by google app script when making new sheets or changing sheet name or duplicaing sheets or deleting sheets from google spread sheet
:::::: I need list of sheets name ::::::::::::
There are many sheets
New sheet will be added by other user
Name of new sheet will be changed by other user
some sheets will be deleted by other user
I need existing sheets name list not past
::::::::::::::::::::::::::::::::::::::::
and the list of sheet name should display on second sheet that code expression is sheet[1]
below code are working well. but it's not refresh by adding sheets or deleting sheets
function sheetnames()
{
return SpreadsheetApp.getActiveSpreadsheet().getSheets().map(function(x) {return x.getName();});
}
I believe your situation and goal as follows.
You are using the function of sheetnames() as the custom function on Google Spreadsheet.
You have already confirmed that your function of sheetnames() works.
You want to refresh the custom function when the sheet is deleted, inserted, copied and the sheet name is changed.
In order to achieve above, I would like to propose the following method.
Usage:
1. Prepare script.
In this case, the sample script for refreshing the custom function of sheetnames() in the Spreadsheet is run by the OnChange event trigger. For this, please copy and paste the following sample script to the container-bound script of Spreadsheet, and save the script.
function onChange(e) {
var lock = LockService.getDocumentLock();
if (lock.tryLock(10000)) {
try {
const prop = PropertiesService.getScriptProperties();
if ((e.changeType === "OTHER" || e.changeType === "REMOVE_GRID" || e.changeType === "INSERT_GRID") && !prop.getProperty("run")) {
const formula = "=sheetnames"; // <--- Please set the function name of the custom function.
const ss = e.source;
const tempFormula = "=sampleFormula";
ss.createTextFinder("^\\" + formula).matchFormulaText(true).useRegularExpression(true).replaceAllWith(tempFormula);
ss.createTextFinder("^\\" + tempFormula).matchFormulaText(true).useRegularExpression(true).replaceAllWith(formula);
prop.setProperty("run", "done");
} else {
prop.deleteProperty("run");
}
} catch(e) {
throw new Error(e);
} finally {
lock.releaseLock();
}
}
}
In order to avoid the duplicate run of the script, LockService is used.
In order to avoid the infinite loop of the trigger, PropertiesService is used.
2. Install OnChange event trigger.
In order to execute the function of onChange, please install the OnChange event trigger to the function onChange. You can see the method for installing this at this official document.
3. Testing
In order to test above script, after you installed the function onChange as the installable OnChange event trigger, for example, please insert new sheet. By this, you can confirm the custom function sheetnames() is refreshed.
References:
Installable Triggers
Class TextFinder
Lock Service
Class PropertiesService
I am still very new to addons and I am having trouble to install triggers and have the related functions to run.
Below is the function to add 1 "on open" trigger and 1 "on edit" trigger to the sheet.
function addTriggers() {
var sheet = SpreadsheetApp.getActiveSheet();
var triggers = ScriptApp.getUserTriggers(sheet);
if(triggers.length!=2)//
{
ScriptApp.newTrigger('sheetOpen')
.forSpreadsheet(sheet)
.onEdit()
.create();
ScriptApp.newTrigger('sheetEdited')
.forSpreadsheet(sheet)
.onOpen()
.create();
}
Then I tried to install this function through onInstall();
function onInstall(e){
addSpreadsheetEditTrigger();
sheetOpen();
}
function sheetOpen()
{
//do something after the sheet is open;
}
function sheetEdited()
{
//do something when the sheet is edited by user;
}
When I tested this addon, the triggers were not installed and thus none happened. Also please note that I need to use installable triggers because I need to access external files.
Could someone let me know where I did wrong?
1. How to build a trigger manually
If you want to build a trigger for a spreadsheet, you need to specify as parameter in forSpreadsheet() the spreadsheet, not the sheet!
So:
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
...
ScriptApp.newTrigger('sheetOpen')
.forSpreadsheet(spreadsheet)
.onOpen()
.create();
...
It seems that you got the assignment of the functions 'sheetOpen' and 'sheetEdited' the wrong way around
You should doublecheck either you really need to build the trigger manually. Instead you can call the already existing onOpen(e) trigger (unless you need an installable one).
Sample:
function onInstall(e){
sheetOpen();
}
function onOpen(e){
sheetOpen();
}
function sheetOpen()
{
//do something after the sheet is open;
}
UPDATE
Now, the limitations of Addons won't allow you to install triggers directly. Instead, you can create a custom menu giving the user the option to install the triggers when choosing the respective option.
Sample:
function onInstall(e) {
onOpen(e);
}
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
ui.createMenu('MyAddOn Menu')
.addItem('Please click here to get started', 'addTriggers')
.addToUi();
}
function addTriggers() {
...
}
ERROR : You do not have permission to call ScriptApp.newTrigger. Required permissions: https://www.googleapis.com/auth/script.scriptapp.
Having permission problem to create time based trigger
function onEdit(e){
var sheetName = e.range.getSheet().getName()
if(sheetName == "Config")
{
if(e.range.getRow()==2 && e.range.getColumn()==1){
createSpreadsheetOpenTrigger()
}
}
}
function createSpreadsheetOpenTrigger() {
Logger.log("hello")
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('myFunction')
.forSpreadsheet(ss)
.onOpen()
.create();
}
For Simple Triggers, just running the script within the App Script Web IDE is enough and should prompt you with an authentication popup: Simple Auth Steps.
However, to programmatically create new Triggers you need to make sure the onEdit Trigger is Installable! This gives you increased permissions to do what you need.
We need to open up the dev console to set up an installable trigger.
We need to create a new trigger tied to our function. For installable triggers, it is best not to use the default simple trigger onEdit() function name.
Done! We should be able to run our functions based on triggers with increased permission scopes.
I have a container-bound script attached to a Google Sheet for which I've manually added an On edit installable trigger. I'm using an installable trigger rather than a simple trigger because I want the script to run from the sheet owner's account (my account) no matter who the user is who made the edit. The script is as follows:
function checkTimecardRange() {
var activeSS = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = activeSS.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var approvalTimestamp = activeSheet.getRange("V" + row);
var timecardRange = activeSheet.getRange("A" + row + ":V" + row);
if(timecardRange.isBlank()==false) {
lockTimecardRange(timecardRange, row);
}
}
function lockTimecardRange(timecardRange, row) {
var protection = timecardRange.protect().setDescription('Timecard Row' + row);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
It works fine when I run it manually, but the On edit trigger that I set up for it will not fire. I changed the trigger to a test script:
function log(){
console.log("Hello worlds");
}
and that doesn't fire either. Any assistance in getting the onEdit installable trigger to fire would be greatly appreciated. The edits based on which I expect the trigger to fire are manual edits (at this point I'm just typing in random values) and they are made from the account that owns the sheet and created the scripts.
Well, it turns out that it was a glitch on Google's side. All I had to do was delete the trigger, save, then re-add the trigger without any changes, and everything worked just fine. Go figure.