I've been struggling for two days now to allow the users from my organization to edit the protected pieces of a spreadsheet using only the script I made.
I've been through hell and how I made it work in the end is, I made a fake hidden sheet where the data is stored, and then onOpen, I copy-paste that data to the sheet that the user sees (that they cannot edit). I want to make the UX a bit better if possible, and I was hoping there is a way to force the onOpen trigger from the script. I know I probably didn't do this right, but I cannot spend more time researching, so I need to brute-force it now. (I've tried onChange triggers, I've tried setting permissions in my web app, using doPost, and my brain hurts, this is the first time I'm doing scripting).
TL;DR
Is there a way to refresh the whole tab from the script editor? I need to trigger the onOpen event without the user having to reload the page.
To "force" the onOpen simple trigger you have the following options
call onOpen
function respondToChange(e){
onOpen();
}
If your onOpen function requires the event object you will have to emulate it.
function respondToChange(e){
const event = {};
// add the required properties to event
onOpen(event);
}
change the spreadsheet locale by using setSpreadsheetLocale
Related
How to change Google Apps Script locale?
When a function is run by clicking a button or choosing a custom menu item, or through a simple trigger such as onOpen(e) or onEdit(e), it runs under the account of the user at the keyboard.
To trigger a function to run under another account that has rights to the protected ranges, you need an installable trigger.
Related
In the legacy Apps Script Editor you could log e from Google Form submissions.
How is this done in the NEW Apps Script Editor?
function myFunction(e) {
Logger.log(e);
}
To make sure we are on the same page:
If you are going to run a function like this in any editor you are going to get null:
because simply e is not defined and it is only returning data upon trigger executions of this function. But this function is executed by some events depending on the type of trigger you are using. Therefore, you are not going to see anything (that is not null) in the console if you manually execute this function.
After the function is triggered by specific events:
In any editor again, you can go to the execution page to see the details of the execution. In the new editor, you go to Executions:
and you can see a list of all the executions of this particular function. For example, if your function is a simple onEdit trigger e.g. onEdit(e), you will see this upon editing a cell in the spreadsheet:
You can also see the type of the execution, whether it was executed by the script (Editor) or by a trigger (Simple Trigger).
But anyway, trigger functions are not supposed to be executed manually. As the name suggests, trigger functions are triggered upon events. It wouldn't make sense to use a trigger function and need to manually execute it. It would be a regular function then.
I have a template google sheet that our company duplicates for every project.
The final result I want is to have an onEdit trigger that does a POST request. I actually already have this working. The issue stems from this: This trigger cannot be a simple trigger, it must be an installable trigger because according to Google's restrictions, simple triggers cannot make external requests, but installable triggers can. Again, all of that works, I just have to set up the installable trigger manually.
As I mentioned, this is a template document, so creating a new installable trigger manually every time it is duplicated is a real pain. I want to improve my UX by having it done automatically. Now the API documentation DOES detail how you can do this programmatically right here. So it definitely should be possible if I'm reading this correctly.
In order to have this trigger automatically created, I, of course, must use another trigger. In this case, it MUST be a simple trigger or we're back with the same issue.
So I added this onOpen() simple trigger function to my code: (convertAlias is the name of the function to run when the onEdit trigger activates)
function onOpen() {
if (ScriptApp.getProjectTriggers().length == 0) {
ScriptApp.newTrigger('convertAlias')
.forSpreadsheet(SpreadsheetApp.getActive().getSheetId())
.onEdit()
.create()
}
}
When I open the document though, I get no results. The stack logging shows the error as Exception: Action not allowed. The error specifically originates from the create() call.
I thought that maybe there was some issue with creating an installable trigger from a simple trigger so I went for the next best thing, a button. I added a button to my spreadsheet that was linked to the same code as a "generateTrigger()" function. Pushing that actually DID bring up the Authorization screen, which is what is expected. But then after authorizing my account, it then goes on to report the same Exception: Action not allowed. After that initial authorization, it does not ask me again and automatically goes to that error. I get the same results from running the function manually in the editor.
Is there any way I can make this installable trigger happen with any sort of automation? Is this an issue with my code, a permissions issue, or something else?
Thanks
It appears I should have just been passing the sheet and not the ID? Doesn't seem right but getting rid of getSheetId() made it work!
Probably the answer to this is simple but I am having a tough time getting my head around it.
I have a spreadsheet used by many users. I want custom onEdit and onOpen functions to run only for the user who triggers then. For example - if person B opens the spreadsheet, then only his custom onOpen trigger should run, not the custom onOpen triggers for the other users. Likewise if the user edits a cell only his custom onEdit should run.
Currently how I have set it up everyone has his own triggers but they all run the same script every time there is a trigger by any user, meaning the trigger runs 4x for no reason and it's slowing down the spreadsheet, and it also wastes script time usage for the other users who are not opening or editing the sheet.
You can have separate functions for each user and have code dynamically check for current user and run the function of current user only.
See here for getting current user. Link
Assuming the functions are the same but you just aren't wanting it to run for some users, you could use PropertiesService to store a user property to identify if it should run or not. You have to make some UI method to set the property and then you would check for the property at the beginning of each of your functions. Technically the functions would run but you could return out of them if you don't want to finish the logic.
my onEdit() function calling to other function when there is a change in the sheet.
if the user makes the change all works fine.
but if the change was made by google-form (the form fill some cells with the answers it gets) onEdit() does not trigger.
do I miss something?
Yes, you forgot to read the documentation for the simple triggers:
onOpen(e) runs when a user opens a spreadsheet, document, or form that he or she has permission to edit.
onEdit(e) runs when a user changes a value in a spreadsheet.
onInstall(e) runs when a user installs an add-on.
doGet(e) runs when a user visits a web app or a program sends an HTTP GET request to a web app.
doPost(e) runs when a program sends an HTTP POST request to a web app.
and installed triggers:
Even though installable triggers offer more flexibility than simple triggers, they are still subject to several restrictions:
They do not run if a file is opened in read-only (view or comment) mode.
Script executions and API requests do not cause triggers to run. For example, calling FormResponse.submit() to submit a new form response does not cause the form's submit trigger to run.
Installable triggers always run under the account of the person who created them. For example, if you create an installable open trigger, it will run when your colleague opens the document (if your colleague has edit access), but it will run as your account. This means that if you create a trigger to send an email when a document is opened, the email will always be sent from your account, not necessarily the account that opened the document. However, you could create an installable trigger for each account, which would result in one email sent from each account.
A given account cannot see triggers installed from a second account, even though the first account can still activate those triggers.
Consider what would happen if your onEdit(e) was activated by programmatic changes, such as if your onEdit function alters the spreadsheet values...
In your situation, where you want form submission to activate your on edit function, You will need to install a form submission trigger (there is no simple trigger for form submissions).
An example function to receive your form submission trigger:
function giveMeAnInstalledFormSubmitTrigger(formSubmitEventObject) {
if(!formSubmitEventObject) throw new Error("You called this from the Script Editor");
var newEventObject = /* do something with the formSubmitEventObject */;
// Call the on edit function explicitly
onEdit(newEventObject);
}
You can read more about the event objects that triggered functions receive in the Apps Script documentation: https://developers.google.com/apps-script/guides/triggers/events
onEdit() will not be triggered by another script editing a sheet or by a form submission.
You can use onFormSubmit(e) instead depending on what your function does it would be a good idea to use the e parameter of the trigger.
https://developers.google.com/apps-script/guides/triggers/events#form-submit
What i have done is that i created an extra sheet with a cell that is the same where the primarecell is(the cell that changes). Leave it for now. I open the scriptapp and write down the code(the code that should happen if the cell changes). Then i wrte down "if" and take the two value i both cells and make an trigger that goes on every minute. With that said, if The cells are the same the "if" is looping on "true". But if something change on the primary cell, it will be "false" and you use "else". Under"else" you should have what ever function you want when soemthing change in that cell. + You must have a funtion where you insert the new value form the primarycell to the "check cell" if u want this too function as loop. Otherwise the "if" code will loop "false" every minute becuse the both cells are not the same.
My english and explaining is not that good:(
The "fix" (test_onformsubmit) code you gave, I have to manually run it every time there is new data in the spreadsheet. I was wanting it to automatically send the pdf to email when Form is submitted. Is there a way? Because the manual way runs the code exactly like its supposed to, but I want this as an automatic event so I don't have to do anything.
See parent thread of original problem/question
Read Understanding Triggers. This function is an Installable Trigger, so you need to set it up to run when a form is submitted. It's easy - I would have thought a Forms tutorial would have walked through it.
In the Script Editor:
Choose Edit > Current project's triggers. You see a panel with the message No triggers set up. Click here to add one now.
Click the link.
Under Run, select the function you want executed by the trigger. (That's onFormSubmit(), in this case.)
Under Events, select From Spreadsheet.
From the next drop-down list, select On form submit.
Click Save.
From this point on, the function will be triggered whenever a form is submitted to the spreadsheet.
If you plan to share your script, each recipient will need to repeat these steps.
As an aside, you should change the email setting in your script, so it will work for ANYONE.
var email_address = Session.getActiveUser().getEmail();