Google Apps Script To Help Error When Embedding Google Spreadsheet in a Google Site? - google-apps-script

Spreadsheet A is the master data source for the group that welcomes Newcomers to our little town. It has a ton of very sensitive data in it and cannot be public, not even a little bit. (We're talking about names and birth dates of kids and where they go to school . . . keeping Spreadsheet A secure is mission critical.)
So, Spreadsheet B uses an importRange and a query to pull the necessary columns from Spreadsheet A to populate our "Member Directory".
Then, I embedded Spreadsheet B in the group's Google Site. (Feel free to check out the site if you like at www.SewickleyNewcomers.com )
And it works beautifully.
BUT . . . after I shut Spreadsheets A & B down and a few hours go by, if I try to open the webpage that has the Member Directory embedded in it, the embedded sheet says "#VALUE!"
When I then go and open Spreadsheet B again, it says the same thing: "#VALUE!".
UNTIL, I let Spreadsheet B sit for a few minutes. Then, after it's sat for a few minutes, all of a sudden, all of the data populates again.
AND if I go back to the webpage with the Member Directory embedded in it, all's good.
Presumably, the problem is that if Spreadsheet B is not open, it can't pull the data from Spreadsheet A.
But I can't embed Spreadsheet A because there are columns and sheets that cannot be publicly accessible, as mentioned above.
Some details:
Both Spreadsheet A and Spreadsheet B are currently set to "Anyone with the link" as the sharing preference. (Although I'd ideally like to get Spreadsheet A back to "Private".)
Spreadsheet B is embedded in the Google Site with the built-in Insert Spreadsheet Widget.
Here's the formula I'm currently using to pull the data from Spreadsheet A to Spreadsheet B:
=arrayformula(query(importrange("_","Master!A:Z"), "select Col3, Col2, Col22, Col18, Col19, Col20, Col21, Col24 where Col26='Yes, go ahead and include my contact information in the online directory and in the print directory.' and (Col4='Yes' or Col4='yes') order by Col3"))
Anybody have any thoughts about what's going on here? And ideas for other ways I can get the necessary data out of Spreadsheet A and onto the site (I certainly don't have to go through Spreadsheet B, I just couldn't think of another way to keep all the other data on Spreadsheet A private)? Is there a solution that uses some kind of Apps Script on the Google Site to end-run needing to embed the spreadsheet?
Thanks in advance! And all the people who move to Sewickley thank you, too!

importRange shows what it is expected to show 85% of the time (according to my experiments).
During the other 15%, it shows #N/A or #VALUE.
I believe that if, having found #VALUE on the web page, you just wait a lot (10-15 minutes), then the correct data will come back to the web page, even if you do not reopen the spreadsheets.
Anyway, to avoid this problem, you can make a worksheet "publicSheet" within the master spreadhseet A,
fill it with formulas that copy necessary things from the other worksheets,
and publish this particular worksheet by File>Publish to the web>"publicSheet".
If you do so, still nobody can access the other worksheets of the spreadsheet A,
but the data will never disappear from the published worksheet.

Related

Google Apps Script to add xlsx hyperlinked in gmail into Spreadsheet

I have a very specific task and I found many similar questions but they are all slightly different.
The script is triggered every day at 10am based of the top answer of this post: Is it possible to automate Google Spreadsheets Scripts (e.g. without an event to trigger them)?
I receive a report every day with lines that I want to add into the existing spreadsheet, so I get the report around 8am and then the attached data is added to the spreadsheet through the script.
The situation is that the email is an automated report from Amazon Display Advertising Analytics (Amazon DSP) and the xlsx file is hyperlined, not attached.
So the script, ideally gets the email list from my gmail account, searches for a specific email and retrieves a result. Gets the hyperlinked excel file and copies the content, except for row 1 which are the headers. Adds the content to an already existing spreadsheet.
In the end, I had the help of a Fiverr professional who scripted the code, so out of respect for him I won't publish his work, so if you are interested in it or if you need it, write me a private message!
In the end, I had the help of a Fiverr professional who scripted the code, so out of respect for him I won't publish his work, so if you are interested in it or if you need it, write me a private message!

Recording any copies made of a google sheet

I would like to create a Google sheet that records any copies that have been made of another Google Sheet even when the user creates a copy by putting 'copy' into the URL (https://docs.google.com/spreadsheets/d/"spreadsheet-ID"/copy).
I have found a solution on the post: Track number of copies made from a google spreadsheet but this doesn't record copies made when changing the URL as the above example.
I would like to know the whole URL of the sheet preferably but just the Spreadhseet ID would still be enough for me.
Has anyone got any ideas how I can record all this data onto a spreadsheet please?
Basically you won't have access to see who is copying your sheet if you use the built-in Make Copy.
What you could do is integrate part of the question you have provided, while disabling the built-in sharing method. So the only way to copy your sheet could be through a custom function you can control and register every time it executes.

Navigation in published Google Sheets

I need to publish a report I have in Google Sheets, but since the report is very big, with many sheets and tables, I have hyperlinks set up for easy navigation, that take you to ranges in other sheets.
When I publish the sheet, the hyperlinks stop working (they take you to the first sheet in a new browser tab). I also tried with a script to change the pages with a button, but the button is not clickable in the published page.
Thanks for any tips you might have.
EDIT:
I've prepared a test sheet to see if I find a solution for this. This is a link with permissions to edit:
https://docs.google.com/spreadsheets/d/1ZGw_6WjrkcNKdFvS8gIG46gEMfMuw7ex86SR9C7qXTU/edit?usp=sharing
And this would be the published version:
https://docs.google.com/spreadsheets/d/e/2PACX-1vTa8JDNMzwdvk87kCvbjJXYgK2RGiKy503eJn6eEjxbyU8oIsuvuKTNXCM6yRP16KXrnD9yvLV3J488/pubhtml
This actually works in Excel, I can embed the report and the hyperlinks still work fine, but I have everything else in Google Sheets, so I'd like to find a workaround.
You need to use proper query parameters. The sheet id, gid must be set to navigate properly. You cannot use rangeid. You can however use range.
/pubhtml?chrome=false&gid=[YOUR_SHEET_ID]&range=A1:B1
You can get your sheet id by visiting your sheet(tab) in your spreadsheet (edit version) and inspecting the url.
Your published sheet probably retains the original #gid (which is Google's sheet ID used for local links). This will fail because it is linked to a Spreadsheet that is inaccessible to the new report. Please check if this is the case (you'll see in the links you've created). I can understand that you won't want to share the original reports but you can set up a small test Spreadsheet with a few linked sheet ranges to test the process - please share that.

Importrange on google sheets showing data from days ago that's no longer there?

I have two Google Sheets set up.
Master Roster, which has many sheets inside.
Locale is Australia.
Secondary Roster, which has nothing but a sheet to grab data using import range.
Locale is Australia.
I'm using =IMPORTRANGE("https://docs.google.com/spreadsheets/d/<sheet ID>/edit", "Overview Frontend!A1:j15")
Which was working fine yesterday! But, when viewing the sheet today, the data that importrange is showing is from the last time I used it yesterday.
If I remove the formula and then re-add it, it still grabs yesterdays data. If I view the master sheet, I can see the data has changed.
The data that is being displayed by import range doesn't exist anywhere?!
I even dropped in a script to re-pull the data, still shows stuff that is 24 hours old.
function myFunction() {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange('A1').setValue('=Now()');
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange('A1').setValue('=IMPORTRANGE("https://docs.google.com/spreadsheets/d/<sheet ID>/edit", "Overview Frontend!A1:I16")');
Both sheets are set to refresh on change, but that doesn't seem to be the problem, as the data is changing and refreshing, but just isn't getting pulled across.
It's possible that it's a Google Sheets performance issue / bug or even that one your your spreadsheets is broken. Try to replicate the problem by using other new spreadsheets, one for Master Roster spreadsheet, another for the Secondary Roster spreadsheet. If the problem persist, report your issue both by using Google Feedback (Go to the Help menu, then click report a problem) and by making a post on the official Google Docs Help Forum / Community (go to https://support.google.com/docs then click on the Forum / Community link on the top-right of the page)

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);
}