I'm trying to trigger a function on a cell in a particular column being edited. I'm trying to work out what parameters are available for me to work with, but I can't seem to log them. I have created the following which I've taken from here: https://developers.google.com/apps-script/guides/logging#stackdriver_logging:
function onEdit(e) {
console.log(e);
Browser.msgBox('somethign was edited');
}
If I edit a column, I get the pop-up, but there's nothing logged in the Execution Log. How do I get the data to show in the Execution Log?
Here's how to get the parameters:
function onEdit(e) {
Logger.log(JSON.stringify(e));
}
After copying this into the script editor and saving it with no errors. Just go to any page and perform a manual edit. Then come back to script editor and view executions you can access it from the menu to the left in the new editor. Read the info section of the top entry and it should contain the JSON of the event object
Related
I have two combo boxes in cells that are populated by ranges in the sheet. When the first one changes, I build a URL and call:
var resp = UrlFetchApp.fetch(url, {"method": "get","muteHttpExceptions":false});
And it populates a 2nd range which controls the 2nd combo box. This works just fine in debug mode. But my goal is for this to work using the onEdit mode. If the first combo box is changed, the method runs and populates the second. Using this statement:
mydoc.getActiveSheet().getRange(15, 1).setValue("Some debug message");
I have it placed throughout the method to see where it dies. I have a statement right after the UrlFetchApp.fetch() method that never writes, so I know that's where the problem is. Can you make these types of calls during events?
Again, it works just fine running it manually via the script editor, but not when called from onEdit.
I see this question where they do not allow it, but the last comment in the thread said he got it to work by attaching another custom method to onEdit. I call URLFetchApp from another method, but I tried creating a myOnEdit function, and called URLFetchApp from there, but it still fails. Not sure what he meant by manually attaching to the event...
Using a simple trigger:
function onEdit(e) {
var response = UrlFetchApp.fetch('http://www.google.com/');
Logger.log(response.getContentText());
}
I get the following error (View -> Execution transcript):
Execution failed: You do not have permission to call fetch (line 2, file "Code") [0.008 seconds total runtime]
One possible workaround is to create a installable trigger:
function myOnEdit(e) {
var response = UrlFetchApp.fetch('http://www.google.com/');
Logger.log(response.getContentText());
}
/*
In the Spreadsheet, create new trigger:
Run: myOnEdit
Events: From spreadsheet
On edit
*/
I have a new Forms response spreadsheet that I'm trying to trigger off. I don't make changes (yet) to the default myFunction() method and try to add a trigger. The first field tries to auto-populate forever, spinning and spinning, while I get this error message:
You cannot create a trigger without a target function, please add functions to the attached script.
I've done some online searching, and there are very few similar issues out there, and zero solutions for me.
Before creating a trigger either manually or programmatically you should save the Google Apps Script project.
Tip: Replace the default project name by something descriptive otherwise you might eventually end with a lot of "Untitled project".
One advantage of doing this programmatically from the script editor is that when clicking on the Run button if the script was not save at least one time it will prompt for the project name and save the project.
Resources
https://developers.google.com/apps-script/overview#your_first_script
ScriptApp.newTrigger("must have a function name here not a function declaration")
function imanoob(e) {
Logger.log(JSON.stringify(e));
e.source.toast('I am a noob');
}
Copy both functions into script editor and save them.
Run the second one first and then edit any cell on any tab or sheet.
function createImANoobTrigger() {
if(ScriptApp.getProjectTriggers().filter(t => t.getHandlerFunction() == 'imanoob').length == 0) {
ScriptApp.newTrigger('imanoob').forSpreadsheet(SpreadsheetApp.getActive()).onEdit().create();
}
}
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 written the script below to hid all rows that have a specific box checked. I set a trigger using the clock and every 10 minutes but instead seems to run every time I check a box and it screws up the view every time I check it. I would like to change it to a manual trigger that is a button along the top bar that someone manually clicks. Can anyone help me edit it?
function onEdit(e) {
var s = SpreadsheetApp.getActive().getSheetByName('2 Week Snapshot');
s.showRows(1, s.getMaxRows());
s.getRange('C:C')
.getValues()
.forEach( function (r, i) {
if (r[0] == 1)
s.hideRows(i + 1);
});
}
As mentioned by I'-'I, the name given to your function causes your script to run when an edit is made to the sheet. From the Apps Script documentation on Simple Triggers:
To use a simple trigger, simply create a function that uses one of these reserved function names:
- onOpen(e) runs when a user opens a spreadsheet, document, presentation, or form that the user 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.
The e parameter in the function names above is an event object that is passed to the function. The object contains information about the context that caused the trigger to fire, but using it is optional.
Renaming your function to avoid binding this simple trigger will prevent edits of your sheet from triggering your function.
Documentation to look at:
Guide to Menus
Guide to Triggers
Are there restrictions on what may be in an Apps Script library to be used by Google Spreadsheets? Specifically, can a library include an HTML dialog?
I've created a spreadsheet script that adds a menu item to present the user with a dialog box. It uses
HtmlService.createHtmlOutputFromFile('mappingForm').setSandboxMode(HtmlService.SandboxMode.IFRAME)
as described in https://developers.google.com/apps-script/guides/html/communication. The HTML file includes HTML, CSS and JavaScript with jQuery. It uses google.script.run to populate the dialog with data from the spreadsheet and to submit a form to it.
This all works fine in the original spreadsheet.
I need multiple spreadsheets to use this same code, however, so I'm trying to follow the general idea of Google Spreadsheet Scripts shared across spreadsheets (not libraries) to have a master script with a spreadsheet template and multiple copies.
I followed the directions at https://developers.google.com/apps-script/guide_libraries to create a library from the original spreadsheet. When another spreadsheet uses the library, I'm able to get the dialog to appear, but all calls back to the server (either to populate the dialog or to submit a form) fail with an error caught browser-side by the google.script.run.withFailureHandler as an Error object with properties:
message: "We're sorry, a server error occurred. Please wait a bit and try again."
name: "ScriptError"
I've placed Logger calls in the apps script to see if the server-side functions are being called but none of them are being hit. The script editor's Execution Transcript shows:
[14-12-27 19:38:05:340 PST] Starting execution
[14-12-27 19:38:05:372 PST] Execution failed: We're sorry, a server error occurred. Please wait a bit and try again. [0.0 seconds total runtime]
The client is making the call, but something is failing before it reaches the spreadsheet script.
This makes me wonder whether
I need to do something differently for the code to work as a library.
Libraries can't have dialogs.
There's a server bug.
Thanks in advance for any suggestions.
I was able to have a working library containing an HTML dialog by doing the following.
Move the script and HTML files from the original spreadsheet to a standalone script project. Take note of the library's Project key in the Info tab of File > Project properties.... It will be needed by any spreadsheet that intends to use the library.
If the standalone script project is to used by others, click its Share button to make it shareable to anyone with a link, otherwise it will silently fail for them.
If the HTML dialog needs to call back to a library function (to get or submit data), the library function must be present in the spreadsheet that uses the library, or you'll get an error message in the browser's JavaScript console.
In the spreadsheet that uses the library: Tools > Script editor... Click Resources > Libraries.... In the "Included Libraries" dialog box, enter the standalone project's key in the Find a Library text box, click Select, then choose the appropriate Version, change the Identifier, if necessary, and Save. The Identifier value creates an object of the same name for use by the spreadsheet's script to call library functions. In my case, it is SignupFormResponsesSheet.
In the same Script Editor's code editor, add wrapper functions that call library functions, including any that will be called back from the HTML dialog. My library has an onOpen() which creates two menu items to show HTML dialogs, so I added
function onOpen() {
SignupFormResponsesSheet.onOpen();
}
function showMappingForm() {
SignupFormResponsesSheet.showMappingForm();
}
function showSubmitForm() {
SignupFormResponsesSheet.showSubmitForm();
}
My HTML dialog has a number of callbacks to get and submit data, so rather than writing a wrapper function for each, I added one function to cover all of them by taking advantage of the way Apps Script treats a library as an object containing functions. The first argument is a string naming the library function to call. Any additional arguments are passed to the library function.
function runSignupFormResponseFunction(funcName, varargs) {
return SignupFormResponsesSheet[funcName].apply(this,
Array.prototype.slice.call(arguments, 1));
}
Because of the restriction identified in step 3 above, the JavaScript in the HTML dialog uses google.script.run to call the runSignupFormResponseFunction whenever it needs to get or submit data. For example, it has two lists that are dynamically populated with server data from the library's getRangeLabels and getColumnExamples functions (and one must be populated before the other), so the code is
google.script.run
.withFailureHandler(showError)
.withSuccessHandler(function(ranges) {
loadRanges(ranges);
// once ranges are loaded, load columns
google.script.run
.withSuccessHandler(loadColumns)
.withFailureHandler(showError)
.runSignupFormResponseFunction("getColumnExamples");
})
.runSignupFormResponseFunction("getRangeLabels");
This worked for me today. I hope it works for others who may find this question.