Google Apps Script, calling function once when document is copied - google-apps-script

I have been playing around with Google Script Editor and I've gotten heaps of use out of it.
The next task that I am looking at is automatic formatting and text insertion/replacement when copying a Template.
An example use case is as follows: Within my organisation I have submitted a Doc to the template gallery. When creating a copy of the template I want it to automatically insert today's date and the current time (rounded to the nearest hour).
This is a question about the Triggers. The text replacement bit is easy and done. Not to mention this is just one of the basic use cases, I'll be attempting many more similar behaviours with things like timesheets and the like.
The problem that I am running into is that I can't seem to get the triggers to work as I'd like them to.
2 of the Triggers that I thought I could try and use: onOpen(e) and onInstall(e).
onOpen(e), though it works, it works "too well". That is, it also replaces the text on the original template as well, proving a nuisance when updating info in these templates.
onInstall(e), I thought this would work as creating a copy of the Doc also "installs" the script as well. However this function doesn't seem to run at all.
Any ideas about getting a trigger to happen once and only once when a Doc is created from a template?
Cheers,
Bricktron

First of all, Trigger onInstall(e) works only for Add-ons.
Now coming to onOpen(e), in my opinion you can use Google Apps Script Property's Services to store one flag which helps your code identifying whether this file has been opened or not.
So for very first time onOpen(e) runs, assign property eg: propertyService.setProperty("opened","TRUE") and next time you can check by accessing the property whether it has been already "opened" or not.
Example:
var openedFlag=propertyService.getProperty("opened");
if(openedFlag=="TRUE"){
//Document has been modified
//Do not run the modifiable code again
}else {
//First time
//Edit the file
//Set the propertyService to "TRUE"
}

Related

Looking For Solution to Automate Calendar Event Creation from Google Sheets

Background:
At my (new) job, we have a number of Sales Reps who book gigs for our organization. Until now, they handle all of their sales tasks in our CRM (Pipedrive [PD]). They then use that information to create an "activity" (event) on PD's calendar, which is set up for two-way sync with our general work Calendar (Outlook [OL]).
Problem:
Between the number of different Reps who edit the PD Calendar, the variety in bookings for our org, and just general human error, our Calendar system is a NIGHTMARE. Formatting inconsistencies, typos, lack of necessary information, and even straight up wrong details make my job (creating a program around, and then organizing the talent for each booking) nearly impossible.
"Genius" "Solution":
Even though it's a mess, I hate the type of person who comes into a new position and instantly tries to make changes to a system that has (somehow) worked before their arrival. So instead I sat down with the reps, learned what their needs were for the calendar, as well as their process, and built a system that not only gives me what I need, but also cuts the busy work on their end in half.
Previously, they not only entered into into PD, and then manually created the events, they also created three separate supplementary Word files that documented the details, created a detailed schedule of events, and outlined contractual needs based on the type of event.
So to solve all of this, I created a Spreadsheet (SS) Template that had all the fluff prefilled, was able to fill in all the contact info from an external contact database, and fill in the entire event schedule based on "type" and "start time". So basically they just need to enter in "Where", When", and "What", and the SS would auto populate the rest.
How that benefits me, is I then painstakingly scoured YouTube, Reddit, and Stack overflow for information on how to build Scripts for Google. And managed to make a function that can pull all the information from their new fancy form, and automatically create a 100% accurate and consistent Event for me.
Everybody wins, right?
New Problem:
Due to things well beyond my current knowledge, I am unable to create a dummy proof way for the event to "Trigger". I know it has to do with user permissions, and the limitations of Simple Triggers yada yada, but I'm incredibly annoyed that I managed to eliminate so much busy work, entirely solve my problem in the process, and yet the thing blocking me in the end is that I have to actively go to my Script and hit "Run" for it to properly function.
(For any "Expedition Force" readers out there, this feels a lot like how for so long Skippy could program intricate FTL Jumps across Spacetime, but still needed a "filthy monkey" to push the "jump" button)
Relevant Additional Details:
As I said, we use Office, but we're likely switching to Google down the road (and as someone who works in the arts and has been a poor student/struggling artist for the last two decades, I am much more versed with Google than Microsoft. I've also rarely found anything of value within my needs that one could do that the other couldn't, so I've built this whole system in Google Apps Script. However, if someone finds a potential solution where this will work in Excel with VBA instead, then I'd learn to translate what I've written so far.
Also, the Script works. I can make it work 100% of the time via the Apps Dashboard (where they don't worry as much about permissions), so it's not a problem with the code itself, which is why I haven't posted it here (but I can if anyone has a reason to think it's relevant).
It is a frequent need for our Reps to go in and edit the gig (people get sick, availabilities change, or mistakes were made the first time, etc.), so to combat this, I've actually written two Scripts. The first is a "Create" script which takes all the information, creates an event, and then pulls the EventID # which it pastes in a safe cell on a different tab. The second is an "Edit" script which searches for the previously created event by ID, and then makes the changes as needed.
In addition to PD and Office, we also use Monday.com and have a Zappier account. But I'd rather avoid either of those if possible since they have apparently changed software packages every other year before I got here, and we are in the middle of a search for a new Executive Director, so I'd rather not have this whole thing come crashing down because one minor part of it depended on Zappier, which our next ED cut from the budget, ya know?
Potential Solutions:
I can make the whole thing run via their Installable Triggers. However, I find them limiting:
I can do it by "Open" which creates the event every single time the SS is opened (which is both obnoxious AND useless, since the edits happen AFTER it is opened).
I can do it by "Edit" or by "Change", but again this just creates a whole new Event every time. I even tested it and made three random edits on empty cells in a useless tab, and it made three identical events to match the first (although this could be a solution for my 2nd Script...). I wish they could do onEdit of specific Cell, because THAT would be useful.
I can do it by form submission.. which means I can instead make a form that they fill out that creates the whole doc, and after they submit, it creates the doc AND event, but this limits the idea of having a different SS for every contract.
And lastly, which I really want to avoid, since I don't trust the Reps who manage to spell the same name wrong three different ways in three different places with having to open Scripts and hit "run", I could create a macro that notifies ME whenever changes are made, and then I could go in and manually hit the button. But..... Is that REALLY the best solution?
I know that's a lot, but I'm more looking for creative coding ways to solve a general problem, rather than a specific fix to a single string. Anything that could make what I want happen, without making me do annoying extra steps, or without requiring me to trust others with a keyboard, I am open to suggestions!
You would benefit from more research on triggers gerenally, onEdit in particular. It is broadly true that onEdit is triggered "when anything was edited" but the script can be written so that it evaluates specific rows &/or columns &/or cells &/or sheets &/or values. It can do this by using Event Objects which involve including an argument (often the letter "e", or the word "event"). The Event objects provide a lot of information about the nature of the edit.
For example, if you had a checkbox in sheet "Sheet2", column D, and you wanted to trigger something if the checkbox value was changed to "checked", then an onEdit(e) script might include an IF statement such as:
if(e.range.getSheet().getName() == "Sheet2" && e.range.columnStart == 4 && e.value == true){//do stuff}
In the scenario described, an automated trigger might not be necessary - a user might select a row (or a cell in a row), and click the "Button" in order to execute the script. However, it might be desirable to "check" a checkbox so that there is no doubt about that row has been calendarized or not. The advantage of this is that an event is not calendarized twice.
The following script might be an appropriate example:
function buttonTrigger() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheetName = "Sheet1"
var sheet = ss.getSheetByName(sheetName)
// get the row to be calendarized
var row = sheet.getCurrentCell().getRow()
// Logger.log("DEBUG: the cursor is on row is "+row)
// check is this row is already processed
if (sheet.getRange(row,4).getValue == true){
// this row already processed
// insert abend code
return
}
else{
// this row is OK to update
// insert script to calendarize event
// update checkbox to show event is updated
// checkbox is in Column 4
sheet.getRange(row,4).setValue("true")
}
}
Example
Creating a button and assigning a script
There is a good explanation of this process in StackOverflow topic Run script only on click on button instead with open the sheets

How to avoid saving a google sheet and have multiple people editing at the same time?

I’ve created a Google Sheet – kind of like an app – using script. It’s a number of blank cells where once added some information, it creates a string with that information in the right order. I created this to help some colleagues. We are using free accounts.
I face 2 problems:
The app is supposed to be used by only one person at a time, but I’m sure at some point two or more people will want to use it at the same time. Is there a way to allow this without they interfering with each other? I’ve read you can share a link that creates copies of your doc, but that wouldn’t work in this case because I intend to keep updating it regularly.
The changes people make to the sheet will stay there. Right now I have a onOpen function that just rewrites everything, but if someone accesses the document while someone is using it they’ll rewrite everything and ruin their work.
Any ideas on how to solve these two problems? Thank you so much in advance!
I think that you have to find another way to implement your "app" because Google Sheets not a good tool for limiting that only one user edit a spreadsheet a time, but if for any reason you decide to keep with it,...
... you need to implement a workflow like the following
Save the active user email on PropertiesService.getUserProperties().
This should be done by each user by running a script themselves. The most user-friendly will be by using a macro, custom menu or button (a drawing with an assigned Google Apps Script function). You might use an open installable trigger to validate that the active user have already done this.
You might have to make the function that clears the data a "smart" function.
You might have to consider additional cases, like if the owner of the spreadsheet opens it when there is an editor working on the spreadsheet.
Use installable triggers to manage the sharing settings.
Use an open trigger to remove all the editors except the active user
Use a time-driven trigger to add again the editors. To make this work effectively should define how the time-driven trigger will know that the last editor have finished their session, i.e. you might use DriveApp.getFileById(SpreadsheetApp.getActiveSpreadsheet().getId()).getLastUpdated()
The above should help you with both problems, as long you as the owner do not open the spreadsheet as is used by someone else.
Other alternatives that might work better is to create an add-on or a web application.
Related
Determine current user in Apps Script
Last modified date in Google App Script GAS sheets

Identify External Apps Script That Modifies Google Sheet

There is a Google sheet with a bound Apps script. One of the functions (written by me some time ago) that applies custom formatting etc. is triggered by an installed onEdit trigger (installed by the client). This worked perfectly until now.
The spreadsheet owner (one of my clients) recently complained that when he enters any text into a cell then the cell next to it will automatically get overwritten with "FALSE", and when he edits that "FALSE" then the first cell gets overwritten with "FALSE", which makes no sense at all.
I have checked the original script, which still looks fine, it can not cause this automatic mess creation. To make sure I am not missing something, I have checked, there is only one installed trigger, and there is no other simple onEdit function in the bound script.
I have also temporarily changed the name of the function started by the installed onEdit trigger to disable the trigger. Despite the fact that now editing could not run any function in the bound script, the automatic mess was still active, and something has automatically overwritten some cells when the user is editing.
This makes me suspect that an external unbound script (could be also a script bound to another spreadsheet with a timer trigger) might be the culprit and doing all the mess.
My question is whether or not there is a way to identify any external scripts (not bound to this spreadsheet) that change the sheets?
In this case I can not provide any code or show you the spreadsheet/script because it is confidential, belongs to the client. I can not show you any code that I have tried either. Only the above explanation how I attempted to locate the source of the problem.
Additionally let me add, that in this case more than one people are messing with the sheets and scripts in the background that I don't know who they are. Therefore, there is a chance that some rogue parties are trying to deliberately sabotage my work (if for nothing else, then as a prank).
UPDATE_1
I have made a copy of the spreadsheet, then verified the installed triggers page and there are no triggers installed.
Next, to make absolutely sure that none of my scripts should cause the problem, I have deleted all my scripts. Only an empty project remained, still having the same name as originally. Saved the empty project. Reloaded the spreadsheet and tested again.
The problem still exists: when I edit the misbehaving cells, the cell next to it automatically changes to "FALSE".
I have also made sure that no ARRAYFORMULA is present in those columns.
The right answer to the topic question was first given here by #TheAddonDepot thanks, but for some reason he deleted it. If he re-posts the same answer here, I will accept it as the best answer and give full credit for it. Then few minutes later Rafa Guillermo repeated it as seen above.
The answer is that it is not possible to identify external apps that modify the spreadsheet, but the only chance to find a trace is to look into the version history to see which editors have modified the sheets. I take this as the correct answer as long as someone does not offer a better answer.
In mean time (as explained in the update of the original post) I have stripped down all scripts from the spreadsheet, but the problem was still present. With this setup the only remaining suspects were any addons.
It turned out that there were these two addons visible in the Add-ons menu but they were not installed:
Sheets2GCal
Magic Cell Notifications
Since I could not remove an addon that was not installed, I had to install Sheets2GCal and then removed it right away. This fixed the problem, the automatic mess has stopped.
But, to make sure the other one should not cause any problems in the future, I have installed and uninstalled that one as well.
Thanks again to the contributors.

Bound app scripts and multiple projects

First time I'm working with google app scripts. I inherited a google sheet (template) from a colleague (who no longer works with us) that runs some scripts on change. The script from what I read should be a bound script.
When I open Script editor though, I see 2 projects. One is the copy of an earlier version of the project. Each of them has an onOpen() function. My question is how does the sheet know which one to invoke?
To replicate the behaviour, I created a sheet of my own and then using the script editor, created two projects each with the onOpen function. The function adds some menus on opening the sheet.
I see that both functions are fired, because the menu names are different. However, I don't see the same behaviour in the original template in question which seems to invoke only one of the two scripts.
I checked to see if there are any triggers etc. but none seem to exist. I find no documentation around this either.
They are both bounded to the sheet, as your tests showed both onOpen(e) are being invoked. What you could do to know which of the script was edited last or some details is to check the revision history of each script (in each script file-> see revision history).
I figure the last developer didn't comment the code so he must've disaled one of them by hand
It turns out as I mentioned that both onOpen functions were indeed being fired. Both scripts and tons of code in it but was exactly identical and the end effect was the same on the sheet. Pretty weird.
I fixed it by making a copy of the sheet which let me delete one of the projects and keep just one. I then deleted the original sheet and made my copy the official one (naming it the same).
I'd have preferred if apps script chose to make it unambiguous by mandating explicit triggers to a function on a particular sheet.

onMove() or onCursor() or onSelection() trigger in Google Apps Script?

I've looked at the documentation for triggers, but couldn't find what I wanted. I essentially want to auto-fill certain spreadsheet cells when the cursor/selection moves to the cell.
For example, say I want any cell in column 'B' that is empty to be filled with the current time when it is highlighted.
How should I be doing that? I see Extending Google Sheets refers to UIService and HtmlService, but I didn't find anything about triggers for when current cell changes.
For your particular example, I would suggest creating a custom function Docs for Custom Functions (using apps script) which produces the current time and enters the value in the cell. It doesn't need parameters either. You could then call the function with something as simple as:
=time()
Add a few clicks for copy and paste, and you have a lot of functionality to play with.
Built in functions which produce the current time may or may not update as you reload the spreadsheet.
There are no triggers for the events you describe, and while you may post a request on the issue tracker, I would not expect to see such triggers implemented.
Using existing capabilities, the closest you could get would be a menu-driven function that fills the current cell with a timestamp. Hardly as automatic as you are looking for.