I wrote some GAS code for a person and it required a trigger.
I created this line and asked the person to call it to set up his trigger (as it is his spreadsheet):
ScriptApp.newTrigger("myFunction").timeBased().everyDays(1).inTimezone("Australia/Brisbane").atHour(5).create()
But then, I cannot see his trigger.
To see if a trigger is there I used:
Logger.log(ScriptApp.getProjectTriggers())
It returned an empty array so looks like the trigger is gone but I don't see it physically...
So, if it's a client, it is not cool to ask his "please set up your trigger" and then not be able to see it and then ask to check if it's there.
What's the best way to set up and manage triggers for clients?
EDIT: As stated in the accepted answer, It seems other user's triggers are viewable manually in the dashboard.
Other user's triggers are not available for you to view programmatically/manually for security reasons.
I created this line and asked the person to call it to set up his trigger (as it is his spreadsheet):
You must explicitly create a menu , so that the user may click on it to create the trigger:
If the user sets up a trigger through menu options, You can set the id of trigger to properties service like this.
function createTrigger(){ //to be linked to a "Create Trigger" menu
// Creates an edit trigger for a spreadsheet identified by ID.
var tid = ScriptApp.newTrigger('myFunion')
.forSpreadsheet('1234567890abcdefghijklmnopqc3')
.onEdit()
.create()
.getUniqueId();
//set id of trigger in properties
PropertiesService
.getScriptProperties() //if you want public access to trigger(If not use getUserProperties)
.setProperty(
Session.getEffectiveUser().getEmail() ||
('user1 ' + Math.random().toFixed(3)),
tid
);
//Inform user: trigger created successfully.
SpreadsheetApp.getActive().toast('Trigger created successfully with id: ' + tid);
//#see https://script.google.com/home/triggers
}
To see his triggers, open the editor and choose "Current Project Triggers" from the Edit menu.
On the trigger page, click the "x" on the "Owned by me" filter. Then you shold see all the triggers for the project and know if it is set up. It won't tell you who owns it, I don't think.
You cannot "manage" his triggers from there, just see them. There is no way to mess with other peoples triggers (a much debated topic!) but you can change the name of the function to break a trigger.
Related
I recently asked this in an admittedly overly verbose Post (Here), but I created a Google Script that gathers information from within a Google Sheet and formats it into a Google Calendar Entry, and it works, but the hope was to have a "button" within the Sheet that a user could then Trigger the function to happen.
However, due to how Google authorizations work (or my lack of understanding of them), this doesn't seem possible.
So my question is, what options do I have (by either using a different Script to give me authorization, or by some other annoying workaround) to make this actually work how I'd like it to, which is allow whoever had the sheet open to trigger the event from within by running the function internally (as opposed to opening the Script App, which is currently the only way I can make it work).
Any advice?
function climbevent() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calendar Creation");
var lr = ss.getLastRow();
var cal = CalendarApp.getCalendarById("ee0eb69f0021b2b30a29268670a990408e1c3a128a096676428f9333506568a7#group.calendar.google.com");
var data = ss.getRange("A10:F10").getValues()
for(var i=0;i<data.length;i++){
var event = cal.createEvent(data[i][0], data[i][1], data[i][2],{location: data[i][3], description: data[i][4],guests: data[i][5]})
}
var eventId = event.getId();
ss.getRange('F13').setValue(eventId);
var title = event.getTitle();
if (/Play/.test(title)) {
event.setColor('9');
} else if (/Class:/.test(title)) {
event.setColor('5');
} else if (/Rally:/.test(title)) {
event.setColor('3');
} else {}
}
UPDATE: SOLVED!
Martin provided me with a link below that I was not coming across anywhere else that completely solved the whole thing for me.
Everywhere I looked, I kept finding people link to Google's Installable Trigger explanation, which seemed incredibly lacking on the front of onEdit functionality.
I was really caught up on the fact that the Installable Trigger for onEdit was on any edit, and what I really wanted was the trigger to be specific.
My limited understanding of coding in general led me to think that this version of the Installable Trigger was overreaching, and I needed a different, more focused Trigger.
What I failed to understand (in case anyone ends up in a similar mental trap as me), is that the solution is to create an Installable Trigger for a middle function that nests the desired function is the key.
Installable Trigger logic flow then is:
Trigger: Whenever ANY Edit happens, do function 'X'
X = If Y, then Z
Y = Check specific cell (or range)to see if it has changed (or is of a specific value)
Z = DO Desired Function
This makes logical sense, but I had been looking for (and assuming was possible) that I could JUST create the "onEdit" to focus on the desired cell. It's a shorter chain, but apparently not how this works at all, so I was missing the correct path.
Thanks again, Martin!
What you can do is to set it to run on edit, but as an installable trigger. This way, you make it run by a modification in a cell instead of a button
For example you could have a checkbox in A1, and a function like this with the installable trigger:
function installedEdit(e){
if(e.range.getA1Notation()=="A1" && e.range.getSheet().getName() == "Calendar Creation") {
climbevent()
SpreadsheetApp.flush()
e.range.setValue(false)
}
}
What I usually do is have a dropdown with references to functions, and a similar function with if statements that launches the necessary function according to the option selected in the dropdown. Possibly you won't need it now, but just in case so you have the idea!
Can you insert a Macro command into a link?
I see you can create a button via "insert drawing" and additional script details but I like to click a link and it performs my macro.
You could create a web app and use it's end point url to call any of your functions by name through the use of the parameters in the query string.
You could use the onSelectionChange(event) trigger. If you move the cursor and click on a cell it will tell you which cell was clicked and you could associate another function with that cell. If you click in the same cell it won't do anything.
However what I find is, although it is a simple trigger, you have to close and reopen the Spreadsheet for it to become active.
function onSelectionChange(event) {
// event = {"range":{"columnEnd":3,"columnStart":3,"rowEnd":1,"rowStart":1},"authMode":"LIMITED","source":{},"user":{"email":"xxxx#gmail.com","nickname":"xxxx"}}
Logger.log(JSON.stringify(event));
}
I would like to get a trigger to run a specified amount of time after an edit occurs.
I'm thinking that I could someone combine an edit trigger and a time based trigger for this functionality, but am not clear how.
To provide some additional detail.
I have a Google Sheet where I track my insulin usage. I am supposed to check my blood sugar 2 hours after I administer my insulin.
When I administer the insulin I make an entry into Google Sheets, time/amount/etc... When I make this entry I would like to create a trigger that will run in 2 hours to send me an email notification as a reminder to check my blood sugar again and make a new entry.
This is how I use time triggers in Google App Script.
Function to create the time trigger.
function createTriggger(name,action,time){
// Time is in minutes
var trigger = ScriptApp.newTrigger(action)
.timeBased()
.after(time*60*1000)
.create();
var triggerID = trigger.getUniqueId();
// Store trigger id to delete the trigger once it has executed
PropertiesService.getScriptProperties().setProperty(name, triggerID);
};
This name is the name of the property to store the trigger id, so you can delete the trigger after it executes. action is the name of the function you want the trigger to execute, and time is in minutes.
On the last line of your function that you want the trigger to execute, use this line to grab the trigger id and delete it from your trigger list. Put the name of your trigger id property in name.
var triggerID = PropertiesService.getScriptProperties().getProperty(name)
deleteThisOne(triggerID)
Here is the delete funciton:
function deleteThisOne(id){
var triggers = ScriptApp.getProjectTriggers();
for(var i=0;i<triggers.length;i++){
if(triggers[i].getUniqueId() == id){
ScriptApp.deleteTrigger(triggers[i]);
break;
};
};
};
Look at google scripts Installable Triggers for Limitations
When your edit trigger fires, you could use a ClockTrigger - see the ClockTriggerBuilder documentation and example, which allows you to either set a time relative to the current execution time, or at an absolute time.
You can use a work around like this:
Set '0' value in some corner cell in spreadsheet which you won't modify ever. Hide that column.
Set onEdit trigger on spreadsheet and write its function, which sets the value '0'.
Set another trigger which is triggered every 10 minutes to increment that cell value by 10 every time. Also add this to that function:
if(cellValue%120 == 0)
{
setReminder(); //function to send you reminder
cellValue = 0;
}
I have a Google Sheet where other users in my organisation have edit access. One annoying problem we're facing is users changing the sizes of the columns.
How do I prevent users from changing the size of any column in the sheet? I am open to using Google Apps Script to implement a solution.
You could try to make use of the "On Change" trigger. It detects a couple of things, one of which is if you modify a column width. The 'changeType' will be "OTHER".
Unfortunately, there isn't an easy way to see what column was re-sized, so you'll have to just reset every column back to whatever the default is. Additionally, this will also trigger for edits, inserting/deleting columns, etc. So you'll have to choose to what level a user can modify the spreadsheet, and otherwise, bailout of the function:
function onChange(e) {
if (e.changeType != "OTHER") {
return;
} else {
//otherwise re-size columns
}
}
Also, it's an installable trigger, so you'll have to enable it. From the script editor:
Resources -> Current project's triggers
Click the link for "No triggers set up..."
If you already have an installed trigger, click "Add a new trigger"
Select which function to Run when a change is detected.
Select 'From spreadsheet' under 'Events'
Select 'On Change' in the final drop-down box.
Otherwise, an installable time-based trigger is also an option, as others have suggested.
So, i made a spreadsheet for Minecraft and 'Feed The Beast' a modpack for the game. My spreadsheet lists all the mods that are updated for the latest version of Minecraft. Recently i made a script to go out and parse pages for mod version numbers. They change hourly-daily and i rather not do it manually.
function GetVersion(url, slice, num1, num2) {
var r = UrlFetchApp.fetch(url).getContentText();
var version = r.slice(r.indexOf(slice)).slice(num1, num2);
return version;
}
In one of the cells Ill have the following
=GetVersion("http://files.minecraftforge.net", "Build 7.", 12, 15)
Now this works fine and gets me the version number im looking for. The problem is, when an update happens and a new version comes out, the parser doesn't reflect this even if i close the window and reopen the spreadsheet or reload or whatever else! If I change the above slightly, like change the 15 to 16, it will refresh, but then will be stuck there again until i manually change it again.
How do I get it so it at least refreshed when i reload the sheet?
Edit: Alright first I tried to go into reosources and triggers and make a trigger very min and everytime the doc is opened. This didn work..............
Then I tried to get clever. Noticing that the formula reevaluates whenever I change it, i surmised that the formula itself or the cell parameters needs to change in order for this to happen. So I pass a dummy parameter though in the formula and change that parameter to update the cell.
But that's annoying and make me have to edit (or press a button) just to get shit to refresh.
So i got a brainwave and Im now passing GoogleClock() in the dummy parameter. All cells now update on their own every 60 seconds. yay
Is there a better way to do this?
Using googleclock as a param is the best u can do if u want to use a custom cel formula.
Instead call an update function from a menu item and/or onOpen / time trigger.
Aside from the workaround of passing GoogleClock() as a parameter (which I agree is the best you are going to do with a custom function), the other option is to do away with a custom function, and use GAS to write the result directly to a cell, eg:
SpreadsheetApp.getActiveSpreadsheet().getRange('Sheet1!A1').setValue(version);
Then in Resources, Current project's triggers, you can set both an "on edit" and time-driven trigger (to be clear: these triggers won't work on a custom function called from a spreadsheet cell; all the "work" must be done by the script itself).