onEdit() stopped working? - google-apps-script

So I have a Google sheet where, when a user enters a number of an item, it will output a description and price. I actually have 50 sheets (one for each state in the US) that are all almost exactly the same, but put out slightly different prices because state taxes vary from state to state.
I used onEdit() to have my sheet work and it was working fine until I changed where the source for information came from. Originally in my sheet, I had another page with all the item information so that a simple Vlookup could do most of the work except calculate the item's price (this is what my code was doing, using the info page that was in the sheet to calculate a price).
However, when an edit needs to be made to an item, I want to make it so that we only have to update one "master" sheet, and make a call by openByUrl(...) instead of going to all 50 sheets and copy pasting the information. I tried implementing this in a sheet, and now it doesn't work when I edit, but it does work when I manually go into script editor and press run. What gives?
EDIT: Here's the code requested.
function onEdit(d) {
itemPriceSetup();
}
// Runs the actual program.
function itemPriceSetup() {
// Grabs and stores the sheet where a customer places an item number and where the code will output the price to.
var orderSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Item Sale Doc");
var orderSheetArray = orderSheet.getSheetValues(1, 1, 34, 8);
// Grabs and stores the sheet that has the information on the item.
//***var infoSheet = SpreadsheetApp.openByUrl('link to info');
var infoSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet with info");
var infoSheetArray = infoSheet.getSheetValues(1, 1, infoSheet.getLastRow(), 10);
So the code with the three asterisks is what I want to use, but causes my the program to not work - that is, it onEdit() won't run (I have it commented out so the code will run - the line below it is the one I'm trying to replace). If I were to go through the debugger with the line un-commented, it actually works.

So I figured it out, but it's a bit strange. I didn't realize triggers for a script are found under resources, so I made put one straight in my script (I guess?). Either way, use the link and go to "Managing triggers manually" to read on how to do it.
https://developers.google.com/apps-script/guides/triggers/installable

I had the same problem onEdit(e) wasn't working. After trying out many different things disabling the new Apps Script V8 engine worked for me. To disable go to Script-menu Select Run and click disable the engine
Dissabling new Apps Script V8 engine
I hope this answer will helps many. I appreciate all of the help that I've received on StackOverflow.Thank you

Related

How to check if user is actively editing a cell

I have a very simple script that is triggered every 15 minutes to re-alphabetize a sheet based on that day's date. It works perfectly, except for one issue. The sheet is used by about 8-10 users at any given time. If a user is actively typing in a cell when the function is triggered and the sheet is resorted, then when they finish typing the cell they have edited the wrong cell. For example, if they start editing cell D24, and then after it is resorted that row becomes D28, then when they hit enter they will overwrite the new D24.
Is there any way I could incorporate something in the code to check if there are any cells that are actively being edited (greyed out because someone is inside it)? Or some other solution that would solve this issue?
function Alphabetize() {
var spreadsheet = SpreadsheetApp.getActive()
var now = new Date();
var name = Utilities.formatDate(now,"EST","MM-dd")
var day = now.getDay()
var sheet = spreadsheet.getSheetByName(name)
var col = sheet.getLastColumn()
var row = sheet.getLastRow()
var range = sheet.getRange(3, 1, row, col)
range.sort({column: 1, ascending: true})
}
Since modals don't work in this situation (time based triggers and other users) I figured out a slightly clunky work around. I added a row at the top of the sheet in the frozen section that is bright yellow and says "Press Enter. Sheet about to re-sort." multiple times so it's visible across the entire sheet. I then hid that row and inserted this code right before it sorts:
sheet.showRows(2)
Utilities.sleep(10000)
So it shows that row, waits for 10 seconds, sorts and then hides the row again with sheet.hideRows(2). Elegant, it is not. But it works on the time trigger and every user sees it. If there's a more elegant solution, I'm all ears.
Is there any way I could incorporate something in the code to check if there are any cells that are actively being edited (greyed out because someone is inside it)?
I think that this could be possible by using a web browser extension that reads the spreadsheet DOM but it will not very dependable as the web page source of many Google apps are generate automatically and anything could change without previous notice.
By one hand, the status identified by the web browser extension should be saved on a document / script store by using the Properties Service or the Cache Service so the time-driven trigger could read the status and by the other, the time-driven trigger save a flag to warn the user using the same services so the web browser could read them.
NOTE: In order to make this work, the web browser should call functions from the same project of the functions ran by the time-driver trigger.
By using Google Apps Script you could use spreadsheet.toast(...) to show a modeles and non so intrusive warning, then use a modal dialog to interrupt the user.

How do I speed up Sheet load times with a lot of importranges?

I've been promoted into developing & maintaining a Google Sheets database at work. I know very little about Google Sheets scripting & from asking around, and researching it's looking like GAS is probably the avenue that I need to start heading down.
So we have 3 Workbooks in Google Sheets; 2 contain large amounts of data, the other workbook provides a UI for our sales dpt. to access the data. I really wish I could share these with you, as describing them is difficult. In the UI workbook, separate pages are paired with sheets in the one database (lets call it database A).
A salesman will go to the UI sheet for the product he's selling a device for; the top section of the sheet allows him to select, essentially, a row from database A. After the selection is made, the rest of the sheet is populated with products we manufacture that work with the choice made in the top section; the products we make are stored in the other database ("B"). We have to have two databases, as we've earlier hit the cell-limit in sheets with the two databases combined.
On average each UI page has about 150 Importranges. Looking up done with Query.
Our problem is that this UI is getting pretty slow, initial load time makes it worthless for salesmen on the road, and annoying to the salesmen here in the office. The delay when making the initial selections (querying database A) is usable, but still much slower then we'd like. And we're not finished building UI pages.
I've seen online that most people recommend using Apps Script to replace importrange, but knowing nothing about Apps Script, I haven't been able to understand what is being done, or mainly how to take the apps script and actually put the data in the cells.
So I'd appreciate any help I could get in speeding this up.
First let me say that the Google Apps script documentation has improved greatly over the years and I find it pretty easy to use now. If you open up a code editor in Google Sheets and go to Help menu and select API reference then that links you up to just about everything you need to know. If you go to the Google Apps reference for spreadsheets and look at the SpreadsheetApp object you'll see that there's three commands to open up another Spreadsheet not a sheet but a Spreadsheet. You can do it by file, by id or by URL.
If you click on the Url command it will take you to an example like this:
// The code below opens a spreadsheet using its id and logs the name for it.
// Note that the spreadsheet is NOT physically opened on the client side.
// It is opened on the server only (for modification by the script).
var ss = SpreadsheetApp.openByUrl(
'https://docs.google.com/spreadsheets/d/abc1234567/edit');
Logger.log(ss.getName());
As it points out, it doesn't actually open the file on the client-side it just opens it up on the server. So it may be necessary for you to open them up manually at first just to get an idea of what they look like. Once you know how they are organized then you can use the open command to get a Spreadsheet Object and from it select a specific sheet and then a data range. Once you have a range then you can load an array like this.
var myArray = rng.getValues();
This will load the entire range in one fell swoop into a JavaScript array and of course it would be nice if you can filter out unwanted data from the array and then put it into your current sheet at a desired range. Note that the range sizes have to be exact matches and also please realize that ranges start from 1 and arrays start from 0 so that can cause you some grief. Also let me add a few caveats that I've run into.
If your dealing with a one row or one column range array then you have to get the array's in the correct form. I tried writing them here but the Stack Overflow text converter keeps messing them up so I'd recommend you go to my reference on that issue here.
If you've coded in JavaScript in the past I'm guessing that you'll have no problem coming up to speed with Google Apps Scripting with the new documentation and an occasional visit to Stack Overflow for a question or two. I've gotten some great answers here from other users. If you need a JavaScript reference here's one that I use.
You are probably best off using a WebApp served from Google Apps Script for the UI which I'd be happy to help with if you had some sample data. If you wanted to still use the sheets, then you could replace the importRanges with some Google Apps Script function that runs every 10 minutes or so to keep the UI sheet updated. It should speed up load times. Something like this would work for you:
function importSheetA() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var database = SpreadsheetApp.openByUrl("DATABASE_A_URL");
var dataToCopy = database.getSheetByName("DATABASE_A_SHEET_NAME").getDataRange().getValues();
var copyToSheet = ss.getSheetByName("UI_SHEET_NAME");
var copyData = copyToSheet.clearContents().getRange(1, 1, dataToCopy.length, dataToCopy[0].length).setValues(dataToCopy);
}

How do I create an Auto-Clear Script in a Google Spreadsheet?

I could use some help with writing a script in my Google spreadsheet. First off, I am no programmer and a novice at best on writing code or any script.
I want to use this for a lunch list. The back story: I created Google spreadsheets to act as a digital lunch sheet. Each teacher has their own spreadsheet for their homeroom and the totals for the class populate a master lunch sheet for the head cafeteria worker for ordering. The problem is that the old totals are still present from the day before. Ideally, on the start of a new day, the specified fields on the spreadsheet will auto clear. Click here to view an example of the spreadsheet I created.
In my research I found a thread on how to create a script to do this, but as a button to click that will then clear specified ranges Click here to see the original post. The script is as followed:
function clearRange() {
//replace 'Sheet1' with your actual sheet name
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
sheet.getRange('C4:I12').clearContent();}
What I would like for is there to be a script so that everyday (say everyday at midnight) a specific field/ range is cleared out. I do not want columns or rows to delete because I do not want to lose student names or lunch selections.
Please, any help is greatly appreciated. Thanks in advance for your help, especially with a novice like me. I look forward to hearing from anyone!
- Jason
Follow these steps...
01. Go to https://script.google.com and then add a New Script.
ᴬᵈᵈ ⁿᵉʷ ˢᶜʳⁱᵖᵗ
02. Paste this function
function clearRange() {
// replace 'Sheet1' with your actual sheet name
// replace 'dhrhrejYOURSHETIDerhe5j54j5j' with your actual sheet ID
var sheetActive = SpreadsheetApp.openById("dhrhrejYOURSHETIDerhe5j54j5j").getSheetByName("Sheet1");
sheetActive.getRange('A:Y').clearContent();
}
ˢᵖʳᵉᵃᵈˢʰᵉᵉᵗ ᴵᴰ ᴱˣᵃᵐᵖˡᵉ
03. Goto Run & select Run function and then select clearRange.
Once you have run the script, your spreadsheet should be cleared.
 
Follow these steps if it works correctly...
04. Goto Edit, Select 'All your triggers'
05. In 'All your triggers' popup windows, select clearRange as the Run function.
06. Set the time as you like. (See the example image)
That script should do what you need. You just need to make a couple of modifications.
Where is says 'Sheet1' you would use 'Lunch' which is the name of your sheet in your example.
In the Script Editor, you can add a new trigger to have the script run every night.
In the Script Editor, go to the top menu "Resources » Current Project's Triggers"
Click the link "No triggers set up. Click here to add one now."
Make sure you set these values:
Run » clearRange
Events » Time-driven
Day Timer
Midnight to 1 am
That should run your script every night sometime between Midnight to 1 AM.
If you want an actual menu item that you can click on within the spreadsheet so you can run the script anytime you want, that's a bit more work. Honestly, if that's your primary function ... it's probably just easier to load up the Script Editor from the spreadsheet ("Tools » Script Editor"), and just select the clearRange function and press the play button.
If you do really want to add menu items, there's additional documentation here » https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#addMenu(String,Object). Once you've coded the new menu function, you'll have to update your triggers just like you did to run every night. But instead, you'll change the event type to From Spreadsheet and set the value to On open. That way it'll create the new menu items when the Spreadsheet is opened.

Contacts not being collected from "Soccer Club Homepage" tutorial

I am new to google apps scripts and I am following the tutorial at https://developers.google.com/apps-script/articles/sites_tutorial and when I run the myContact function from step 1, no contact info is populated into my spreadsheet.
I have a group created called AZ_Pilot, and I have the myContact function set up as follows:
function myContact() {
var contacts = ContactsApp.findContactGroup("AZ_Pilot").getContacts();
SpreadsheetApp.getActiveRange().setValue(contacts[0].getPrimaryEmail());
}
The script runs with no errors, but nothing is updated within the spreadsheet. It's a bit embarrassing to be stumped at step 1, but here we are.
You are using getActiveRange() which is the range which is currently under selection in the spreadsheet. By default, it is the first cell in the spreadsheet. Maybe you have a different cell selected and therefore, the email might be written to a different cell. Try keeping the first cell in focus and running the function again.
Also, you haven't mentioned whether or not there are any contacts in the group you created :)
I was adding some additional logging information, and it just started working correctly with no change to the functional code. Not sure what happened there.

script to force republish of google spreadsheet

I have created a form that pushes data to a Google Spreadsheet. The data is latitude, longitude, location, and other identifying data. The spreadsheet is then published as a .CSV file and imported into ARC GIS to be displayed on an interactive map. It works exactly as I wanted and I set it to republish after each change.
The problem is that when the spreadsheet has rows appended by the script, it is not seeing it as a change and republishing. In order to get the updated data imported to the map, I need to go in and manually republish. Is there anyway through the Google Apps Script that I could make a few lines of code to force a republish? I could then add that to the "on form submit" script I have or another time based one that already runs at 3 am everyday.
I have looked through the Google Apps Script documents and not found anything. When searching for help on the web, the overwhelming majority of responses are for how to publish your script as a template for other.
My testing sheet was republished after the following function was executed by either a menu entry or a time-based trigger.
function ChangeIt() {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var t = new Date()
var x = 'upd: ' + t
var range = sheet.getRange('a3')
range.setValue(x)
}
If I were in your shoes, I'd add an extra column to the end of the sheet with some benign constant data that a script can change without affecting the systems consuming the data. If an extra column isn't an option, try modifying my sample to read in a current value, change it, and immediately change it back.
Also, I'd see if the spreadsheet onEdit() trigger fires when the form submit adds a new row. If so, tie your GAS function to it to force the republish. If not, setup a timed trigger to execute the GAS function.
A quick workaround for this issue that doesn't require scripting is to simply make an array copy of the data.
For example, I made a new tab and in A1 put this: =ArrayFormula('Form Responses 1'!A1:Z1000)
While the main Form responses tab will insert rows and not play nice with formulas this new tab stay nice and constant and updates automatically when new data is added.