I need a clarification about an issue I'm encountering.
When using a function fired by an onEdit trigger, it seems that the script stops executing right after the first instance of a Browser.msgBox() command.
Using a code as simple as:
function notifyStatus(event)
{
try {
Browser.msgBox("Message 1!") ;
Browser.msgBox("Message 2!") ;
} catch (e) {
MailApp.sendEmail("myaddress#mydomain", "Bug" , e.message);
}
}
will bring up the "Message 1!" as expected. But "Message 2!" will never show up and I get no email notification of an error...
Running this in the editor behaves as expected.
What am I missing?
Thanks for any pointer.
onEdit trigger is a Simple Trigger (unlike installable triggers). onEdit trigger can manipulate spreadsheet related objects. It can not send email.
For details, you may look on below two reference links.
https://developers.google.com/apps-script/understanding_triggers
https://developers.google.com/apps-script/understanding_events
If I have this Simple trigger function in my script -
function onEdit(e) {
notifyStatus(e);
}
Then I see both message boxes. However, if I throw an error in notifyStatus I do not receive an email.
But, if I remove the Simple trigger function and create an installable onEdit trigger for notifyStatus; I see both the message boxes and receive an email. The same is true if I run the script manually.
If you use an installable trigger, the email appears to be sent using the identity of the person who created the trigger. It seems that is not the case when using a Simple trigger.
Related
I have to setup "AWS::Events::Rule" in cloudwatch with ScheduleExpression(10 days), and write some code to test it, but I can not change the "10 days" to 1 minute or call the lambda function directly. I know that we can call put event for calling a rule with EventPattern.
But not know how to do that for ScheduleExpression.
Any comment is welcome, Thanks.
To my knowledge there's no possibility for you to manually trigger the rule and make it execute the lambda function. What you can do is change the frequency from 10 days to 1 minute, let it execute, and when it executes switch it back to 10 days
I also met this problem. I checked AWS document and it says that a rule can only contain either EventPattern or ScheduleExpression. But in order to call aws events put-events we must provide a Source for EventPattern match. So I think we cannot manually trigger a scheduled event.
Not sure what's your use case, but I have decided to move to use Invoke API of AWSLambda client.
SDK Approach:
Yes, you can use the putRule SDK function to update the ScheduleExpression of the CloudWatch Rule. As I mentioned in the below snippet
let params =
{
Name: timezoneCronName, /* required */
ScheduleExpression: cronExpression
}
return CloudWatchEvents.putRule(cloudWatchEventsParams).promise().then((response) => {
console.debug(`CloudWatch Events response`, response);
return response;
}).catch((error) => {
console.error(`Error occurred while updating Cloud Watch Event:${error.message}`);
throw error;
});
See this Official AWS SDK DOC.
CLI Approach:
Run the following command though CLI
aws events put-rule --name "You Rule name (not full ARN)" --schedule-expression "cron(0/1 * * * ? *)"
I am using a script in a Google Spreadsheet to, upon form submission, copy an existing spreadsheet and google form to create a new spreadsheet and new form and then connect the new form to the new spreadsheet so the new spreadsheet is receiving the responses from the new form.
The script in the copied spreadsheet is copied to the new spreadsheet, but the installed triggers don't exist. Is there a way to create those triggers from the original spreadsheet's script (the spreadsheet that received the form submission that created the new SS and form) or do I need to rely upon non-installed triggers in the new spreadsheet to create the installed trigger?
Triggers run scripts which require authorization by the user. Because your script is bound to a spreadsheet, it will need to be authorized on each copy.
I have a similar system (copies of a master sheet + code) and we addressed this by adding a custom menu to run a script when someone makes a copy. I added a custom menu and a setup script which would authorize the trigger.
function onOpen(e) {
var ui = SpreadsheetApp.getUi().createMenu("PGP Setup").addItem("Run", "setup").addToUi();
}
function setup() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('makeDocs')
.timeBased()
.everyHours(1)
.create();
}
It's easy on the user who created the sheet and has been reliable for us so far.
I was able to solve my issue with the code below. The function 'newSSTrigger' is in the original script (not a copied one) and is called after the new SS and Form are created and sync'd - this is where the the variable idOfNewSS comes from. The trigger will not create a script in the new objects or even be seen in the new object's scripts as an installed trigger. To find the trigger go to Edit>All Your Triggers from any script. Triggers not greyed out are attached to the document in some way.
This seems to have two benefits:
1) I never have to deal with any permissions - the triggers work without me touching the new docs at all.
2) If I update the 'myFunction' (below) it changes how the existing triggers work because the trigger retrieves its instructions from the original script - in its current state. This means I can update all existing triggers created by this script just by editing this function.
function newSSTrigger(idOfNewSS) {
var newSS = SpreadsheetApp.openById(idOfNewSS);
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(newSS)
.onFormSubmit()
.create();
}
function myFunction() {
do stuff...
}
A different option that would work for people who are not just copying a sheet programmatically (or who are anticipating users making copies that the developer doesn't have permission to edit) is to take care of it for the user inside the bound script. You could use code similar to this:
function onOpen(){
var triggers = ScriptApp.getProjectTriggers();
if(triggers.length == 0){
ScriptApp.newTrigger('yourFunction')
.timeBased()
.everyHours(1)
.create();
}
This says that if there are no triggers, add a time-based trigger. You can see this documentation for variations.
I've create an installable script which creates forms on the fly for 2 to 3 party verification. Since these forms are filled out asynchronously, and often in batches, it is important to determine which form called the function.
First the response form is created, then a trigger is installed.
CreateForm function:
function createForm(title){
var form = FormApp.create(title)
//set parameters for new form
form.setCollectEmail(true);
form.setShowLinkToRespondAgain(false);
...
return form;
};
InstallTrigger function:
function InstallTrigger(form, funct) {
var trigger= ScriptApp.newTrigger(funct)
.forForm(form)
.onFormSubmit()
.create()
return trigger.getUniqueId();
};
During the initial form submit, a function called createMessage() creates an email based on responses and runs the two scripts above. The email contains a link to the newly created form to await approval. To that point, everything works fine.
The problem comes when the newly installed trigger fires. I haven't found a way to set the trigger source as a variable. I'm sure that it has to do with an event, but the documentation on events doesn't go too far into forms from what I can see. I read that it can be done (Understanding Events). I just don't quite understand where (e) is defined on an installable script. Would it be in the install function or some other place?
Thanks again Serge inas for the walkthrough.
(e) is defined when the function defined. In my example above, the InstallTrigger() function adds a trigger to the form passed to it. The script that executes on submission is also passed to it. So, the installation of the trigger comes from a pre-installed onSubmit() trigger. In the submission function, it calls
var NewForm = FormApp.createForm();
InstallTrigger(NewForm, triggerFunction);
The function "triggerFunction" should look something like this:
function triggerFunction (e) {
Logger.log(JSON.stringify(e))
GmailApp.sendEmail("yourEmailString","Debugging",Logger.getLog() //sends an email to you with the logfile.
var form = FormApp.openByUrl(e.response.getEditResponseUrl());
...
}
The e.source mentioned in the aforementioned article says that it works for installable triggers, but when enumerated, only the e.resource and e.authMode were available. Fortunately, the e.response contains the method editUrl that can be used with the method .openByUrl() and return the original form.
I am using jQuery 1.9.1.
Suppose i have a button with id="clickMe"
My jQuery code is:
$('#clickMe').click(function(event)
{
eventHandler1();//do something
eventHandler2();//use output from eventHandler1() and do something
}
Now, i want "eventHandler2" to be executed at last so that i could use the output of "eventHandler1". Is there any way to do this manually and not just the way i have put the handlers inside the click event?
One more thing, "eventHandler1()" and "eventHandler2()" are present in different .js files and thus the requirement.
jQuery.when() provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events.
For example, when the Deferreds are jQuery.ajax() requests, the arguments will be the jqXHR objects for the requests, in the order they were given in the argument list.
$.when(eventHandler1).then(eventHandler2).done(function(){
alert('done.');
});
So can even use GLOBAL variable to store eventHandler1 output and access that inside eventHandler2
Example
var someVar;
function eventHandler1()
{
// process
someVar = some value from process
return someVar;
}
function eventHandler2()
{
alert(someVar);
}
Response to OP comment
as you have asked about execute handler in queue you can use Jai answer.
you can use .when .then and .done as below.
$.when(eventHandler1).then(eventHandler2).done(function(){
//process code
});
i got a question regarding sharepoint workflows and event receivers. i got an event receiver that is setting metadata on an element. after that, i use a workflow to copy item metadata to a list. unfortunately the workflow does not copy the metadata set by the event receiver. i think because it is executed before the event receiver. is there a possibility to change the order, so that the workflow will execute after the event receiver? the receiver ist bound to the ItemAdded and ItemUpdated Events i a syncrounous manner.
Thank you for your help!
Patrick
You can use SPWorkFlowAssociation to run workflow that associate with List or Content Type .
Example ( run workflow after adding item)
public override void ItemAdded(SPItemEventProperties properties)
{
SPList parentList = properties.ListItem.ParentList;
SPWorkflowAssociation associationTemplate =
parentList.WorkflowAssociations.GetAssociationByName("Your Workflow Name",
new CultureInfo
(Convert.ToInt32(parentList.ParentWeb.RegionalSettings.LocaleId)));
SPSite siteCollection = properties.ListItem.ParentList.ParentWeb.Site;
siteCollection.WorkflowManager.StartWorkflow(properties.ListItem,
associationTemplate, String.Empty);
}
More information about SPWorkflowAssociation Check the below link
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.workflow.spworkflowassociation.aspx
SPListItem:
The "Synchronous" events (-ing ending like ItemAdd*ing*), are always executed before the workflow.
The "Asynchronous" events (-ed ending like ItemAdd*ed*), are always executed after the execution of the workflow.
So, you have to set the "Synchronization" property of the Elements.xml file equal to "Synchronous" and the workflow will always be executed after the event receiver.
ATTENTION: Events Added and Updated run asynchronously by default, so you have to do the change in the Elements.xml .