Dynamically Updating Formulas From Another Google Spreadsheet - javascript

I have two google spreadsheets, a master copy and a child copy. When I update the formulas in the master copy, I want it to update the formulas in the child copy too. I intend to create many copies of the child copy and don't want to update the formulas in each one every time something small has to change.
I've tried using IMPORTRANGE(), and it only gives me the values, not the formulas. So I thought to create my own script to get this done. I'm using the following code to attempt this:
function REMOTEDATA(inKey, inRange) {
var outData;
var ss = SpreadsheetApp.openById(inKey);
if (ss) {
outData = ss.getRange(inRange).getFormulas();
}
return outData;
}
//My manifest is the following:
{
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets"
],
"timeZone": "America/Denver",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER"
}
I'm very new to oAuth and I don't understand how to get this to work. When I attempt this it gives me the following:
"You do not have permission to call SpreadsheetApp.openById. Required permissions: https://www.googleapis.com/auth/spreadsheets (line 4)."
Can anyone tell me what I need to add to get this to work? If there's an easier way, I'm all ears.
EDIT:
After reading Ruben's comment below, I changed the way I was doing it to having a button on the sheet itself run the function. It fixed the first problem, but now I'm running into another problem. I can't copy all the data directly from one sheet to another. I'm trying to get formulas, values, and formatting. If I just use getFormulas() and setFormulas() with the ranges, it gets rid of all the values that aren't formulas, and it doesn't change the formatting. I've been trying to use copyTo() but it tells me I can't do this between spreadsheets. My current code is:
function REMOTEDATA() {
var MASTERKEY = "key";
var UPDATERANGES = ["A1:B200", "C7:C200", "D1:H200", "J1:L200", "N1:S200", "U1:X200", "z1:ac200", "AE1:AH200", "AJ1:AL200"];
var ss = SpreadsheetApp.openById(MASTERKEY);
var cur_ss = SpreadsheetApp.getActiveSpreadsheet();
UPDATERANGES.forEach(function(range) {
data = ss.getRange(range).copyTo(cur_ss.getRange(range));
});
}
My head is starting to hurt looking at the different methods for the Ranges Class. I can't see any methods to do this, but I feel like I'm missing something. Any other ideas?
EDIT 3:
Okay. I figured out a workaround. Basically what I did was copy the entire sheet from one spreadsheet to the other using the sheet.copyTo() function. Then after that I used the range.copyTo() to get what I wanted. Then I deleted the copied sheet using sheet.deleteSheet()

Custom functions run anonymously so they can't call services that require authorization, like openById.
Instead of using a custom function to execute your script use another method like a custom menu, assign the script to an image, etc. or just run it from the script editor.
NOTE: You will have to modify your script a bit or use a another function to pass the required arguments.

Related

Editing one Spreadsheet from another Spreadsheet in Google Apps Script

Question
How do you edit two different spreadsheets from one connected script that is triggered by an onEdit command?
My Case
I am trying to create a master spreadsheet that sends and deletes information to two other spreadsheets. I have an onEdit function that once a checkbox is checked, it will send specified information to another sheet.
What I've Tried
To open the other spreadsheet I first tried the openByID function but through a little research I don't believe it is possible to edit another spreadsheet through a script that is bound to a spreadsheet. So I created a standalone script (named MasterF) that I deployed as a library to store my function so that I can call it later. I added the library to the master spreadsheet and am using it to call the function but it keeps throwing an error saying, "You do not have permission to call SpreadsheetApp.openById." All of my apps scripts have full permissions to edit, delete, etc. I've also made libraries out of the scripts bound to the other spreadsheets I want to connect and added those libraries to the MasterF library to see if that would help. I still get the same error message when the on edit function, despite trying to use a standalone script. Maybe I missed something, or it is entirely possible that I can't do what I'm trying to do.
Script
This the beginning of the custom function that I created. Essentially when an onEdit function is triggered, data from spreadsheet1 in the "submit" sheet, is transferred to spreadsheet2 in the "dashboard" sheet.
function DataSend() {
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var submit = ss.getSheetByName("Submit");
var selldata = submit.getRange('E23:I23').getValues();
//#NotOnlyCurrentDoc
var dash = app.openById(<sheetid>).getSheetByName("Dashboard");
Here's the onEdit Function in the script that is bound to spreadsheet1 (not directly a part of the MasterF library) that triggers the datasend function that is kept in the MasterF library.
function onEdit(e) {
var sheetName = "Submit"
var range = e.range;
if (range.getSheet().getSheetName() == sheetName && range.getA1Notation() == 'K23' && range.isChecked()) {
MasterF.DataSend();
}
}
To edit two different spreadsheets from one connected script that is triggered by an onEdit command, you need to install a trigger. A simple trigger does not have the permissions required to edit multiple spreadsheets. Ref. In my question I was trying to use a standalone script and multiple libraries. This is unnecessary. All you need to edit multiple spreadsheets from a single script is an installable trigger.
In my case, I used the following function to create an installable trigger:
function EditTrigger() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ScriptApp.newTrigger('Edit')
.forSpreadsheet(ss)
.onEdit()
.create();
}
'Edit' is the name of the onEdit function I used to detect the changes made in the first spreadsheet. If an If statement in the onEdit function is true, then it runs a separate function that edits two different spreadsheets. After writing the EditTrigger() function, run it manually in apps script and accept permissions if necessary. Now, when the onEdit function ('Edit') is triggered, it should be able to edit multiple spreadsheets.

Getting Values out of Websocket Functions

I am working on a project which needs to get communication from C++ code to JavaScript on a webserver. Currently, I have data sending properly and it's being received but the issue is that I cant use the data outside of the inner(onmessage) function. This still works fine to overwrite elements of the webpage, but the charts I'm trying to build cant get the live data. If I put the code for the chart inside the inner function the entire program freezes and I can't get the variable out of the function for me to use it in the parent either. Right now, I just want to get the data out of the inner function so I can use it. So, is there any way for me to pull that data out of the inner function and use it in the parent function?
Here is my code:
{
var x;
var ws = new WebSocket('ws://localhost:10011/');
ws.onmessage = function(event)
{
x = event.data;
var testing = document.getElementById('InnerFunctionOutput');
testing.innerHTML = "Run Time: " + x;
}
var testing = document.getElementById('ParentFunctionOutput');
testing.innerHTML = "Run Time: " + x;
}
When I run this code the output from the inner function is the constant stream of data and the output from the parent is a constant 1. If anyone could help me find a solution, it would be greatly appreciated.
One alternative solution is to put the functions for the charts inside the websocket function. That way, I wouldn't have to get data out of the function. however, this solution has its own set of problems. I will put a link below to a thread where I ask about this alternate solution if you are interested in that part.
Plotly and Websockets
Any help would be greatly appreciated.
Thanks,
Luke
I found a solution to the problem. To get the data out of the websocket function I overwrote a text element on the page and simply made that element invisible. After that, just read the text element in order to get it into the rest of the code. However, there could be a better way of doing this so please let me knw if there is.
Also, there is one issue I ran into with this solution. When I originally tried this with normal formatting document.getElementById('some id').innerHTML = some data; it didn't work. But when with adding "window" to the beginning window.document.getElementById('some id').innerHTML = some data; it just worked.

Authorization error still persists when calling getDataSourceFormula() even after allowing script to acces Google Sheets

I am trying to get the content of a cell's formula from a custom function that I wrote. I'm just trying to get the formula stored in B2. In Google Sheets. I am getting "Exception: Authorization is required to perform that action. (line 5).". I tried revoking the authorization, adding the next first three lines and authorizing again. Nothing worked.
/**
* #OnlyCurrentDoc
*/
function test() {
return SpreadsheetApp.getActiveSheet().getRange('B2').getDataSourceFormula().getFormula();
}
I can confirm that the error is coming from getDataSourceFormula(). I tried replacing it with other functions, and they worked normally. What is the problem?
Thanks.
You are using incorrectly getDataSourceFormula() as you are combining it with getFormula().
getFormula() returns the top left cell formula of a range while getDataSourceFormula() returns the DataSourceFormula for the first cell in the range. Thus, getDataSourceFormula will only work for data sources, here is more official information regarding what these are.
As you didn't mention anything about data sources in your question I am assuming that you are not using them and therefore you code line should look like this:
return SpreadsheetApp.getActiveSheet().getRange('B2').getFormula();

Display message Google Sheets from Apps Script

I want to display a message on a google sheet. But I don't get it, and, after research here, in documentation, I don't get the answer.
I think that the problem is in "activate" the spreadsheet, where i need to display.
var SEGUIMIENTO = SpreadsheetApp.openById("MyTestediD");
var INF = SEGUIMIENTO.getSheetByName("NameOfSheet");
function TestMessage() {
INF.activate();
Browser.msgBox("Hello")
}
When i run.. nothing happen
I need the definition of Spreadsheet outside the function because I'm working in 2 Spreadsheet's by ID in more that one function.
i only need the correction in my code for display a simple message in the spreadsheet.
PD. i really cant find a simple example of that,
Update
This code it's part of a macro recorder of a Spreadsheet, the same "SpreadsheetApp.openById("MyTestediD");"
I don't know why you try to 'activate' a sheet. If you want display a message I assume you want to do it in the user's current sheet, so:
SpreadsheetApp.getUi().alert('Confirmation received.');
From https://developers.google.com/apps-script/reference/base/browser
The methods in this class are only available for use in the context of a Google Spreadsheet. Please use G Suite dialogs instead.
As you can see, Google is nicely asking you to use G Suite dialogs instead of Class Browser, so be nice too and follow their request.
When you say you want a message in a spreeadsheet, do you mean an alert message? If so, the answer is to use the code SpreadsheetApp.getUi().alert('Hello.'); when the TestMessage function is executed
var SEGUIMIENTO = SpreadsheetApp.openById("My TestediD");
var INF = SEGUIMIENTO.getSheetByName("NameOfSheet");
function TestMessage() {
INF.activate();
SpreadsheetApp.getUi().alert('Hello.');
}

basic import.io html search

So if any of you have any experience with scraping or particularly import.io it will help, since import.io is what i'm using... although I think my question is just about JS really...
I really just want to connect a basic html input to the import.io JS code so I can have a custom search
http://jsfiddle.net/LSng3/1/
"input": {
var search_name = document.getElementsByName("search_name").value;
"search_name": search_name
}
<input name="search_name" placeholder="doesnt work :(">
Heres my go... its the basic working import.io JS example. I tried to add a variable for the input name and add the variable as the search item but that alone isnt working...
I contacted the import.io team and they said they will try to make a easier tutorial in the future but for now try to look at the particle example they have which does include a input to search with but the example is too big for me to deconstruct just to see how the input works.
heres the particle example I uploaded to my server so you can see it working although its a bit slow-> http://www.originalengine.com/scrape/
Please find here a modified version of your code which seems to produce the correct result: http://jsfiddle.net/zNSbk/
This is the modified function:
var doTestQuery = function() {
// Query for tile myTestScrape2
var search_name = document.getElementById("myInput").value;
console.error(search_name);
importio.query({
"connectorGuids": [
"a2201b40-7acc-4a3d-a3ed-30e71e018ffa"
],
"input": {
"search_name": search_name
}
}, { "data": dataCallback, "done": doneCallback });
}
Steps that I took to get this working (not all may be required but it is a summary of what I was playing with):
Redefined the function called by the submit so there's no possible collision with the one that we defined in the script
Moved the creation of "search_name" variable out of the JSON argument to importio.query
Assigned an ID to the input and used that with getElementById rather than using the name (as this would return an array)

Categories