I am trying to access a variable from another script A.gs in script B.gs. they are both in the same document. How could I do this?
I am not sure how I should solve this problem, I am a beginner with apps scripting and I can't find anything on the internet about it.
code.gs:
ui = DocumentApp.getUi();
function onOpen () {
A = prompt('Hello');
}
code2.gs:
function onOpen () {
if (A === "123") {
ui.alert('Hello')
}
}
I want Hello to be output if 123 is entered into the prompt, but when I try to run the code I get the error:
ReferenceError: "A" is not defined. (line 3, file "code2")
In your situation, code.gs and code2.gs are in a project of a container-bound script type of Google Document.
If my understanding is correct, how about this answer? Please think of this as just one of several answers.
Modification points:
In your script, the scripts of code.gs and code2.gs are used as one project at the script editor. So in your script, there are 2 same functions of onOpen() in the project. In this case, only one of them is run. In your case, onOpen() of code2.gs is run and the error of ReferenceError: "A" is not defined. occurs.
Modified script:
If you want to modify your script and you want to work the functions when the Google Document is opened, how about the following modification?
1. Copy and paste the following script to code.gs and code2.gs of the script editor:
code.gs:
var ui = DocumentApp.getUi();
function installedOnOpen () {
A = prompt('Hello'); // or ui.prompt('Hello').getResponseText();
sample(A);
}
code2.gs:
function sample (A) {
if (A === "123") {
ui.alert('Hello')
}
}
Or, if you want to run independently 2 functions, how about the following modification? In this modification, the value is saved using PropertiesService.
code.gs:
var ui = DocumentApp.getUi();
function installedOnOpen () {
A = prompt('Hello'); // or ui.prompt('Hello').getResponseText();
PropertiesService.getScriptProperties().setProperty("key", A);
}
code2.gs:
function sample () {
var A = PropertiesService.getScriptProperties().getProperty("key");
if (A === "123") {
ui.alert('Hello')
}
}
Or, you can also modify as follows. But, in your situation, this might not be required.
function installedOnOpen () {
var ui = DocumentApp.getUi();
var A = ui.prompt('Hello').getResponseText();
if (A === "123") {
ui.alert('Hello');
}
}
2. Install OnOpen event trigger:
In order to run the function of installedOnOpen when the Google Document is opened, please install the OnOpen event trigger to the funciton of installedOnOpen as the installable trigger.
3. Run script:
In your case, there are 2 patterns for running script.
Pattern 1:
Open Google Document.
Pattern 2:
Run installedOnOpen at the script editor.
By above, installedOnOpen is run. And you can see the dialog at Google Document.
Note:
This modification supposes that the function of prompt() returns the value of 123 as the string value.
If you cannot provide the script of prompt(), as a test case, how about modifying from prompt('Hello'); to ui.prompt('Hello').getResponseText();?
References:
Access a variable across multiple script file under a GAS project
Also I think that this thread might be useful for you.
Installable Triggers
If I misunderstood your question and this was not the direction you want, I apologize.
As I can see you define onOpen twice. It does not make sense.
You also don't declare variables and this is reflected in the style of your code. Try declaring the variables and you will realize that your code has no effect.
Related
I want to call the google sheets function ISOWEEKNUM from JS in a custom function and can't get it working.
Current code is
function customFun(date) {
return ISOWEEKNUM(date);
}
However that just leads to an error:
ReferenceError: ISOWEEKNUM is not defined
How can I get that working and is there a reference how to call standard functions?
I believe your goal as follows.
You want to retrieve the week number using Google Apps Script.
You want to use the function customFun as the custom function.
For this, how about this answer?
Issue and workaround:
Unfortunately, in the current stage, the built-in functions of Spreadsheet cannot be directly used with Google Apps Script. And also, the custom function cannot put the formula. So in this case, it is required to use the workaround. Here, I would like to propose the following 2 workarounds.
Workaround 1:
In this workaround, when =customFun(date) is put to a cell, it is replaced with =ISOWEEKNUM(date) using the OnEdit event trigger.
Sample script:
In order to use this script, please put =customFun(today()) to a cell. By this, the formula of =customFun(date) is replaced with =ISOWEEKNUM(today()) by the OnEdit event trigger.
function customFun(date) {return ""}
function onEdit(e) {
const range = e.range;
const formula = range.getFormula();
const f = formula.match(/=customFun\(([\S\s\w]+)\)/);
if (f.length == 2) {
range.setFormula(`ISOWEEKNUM(${f[1]})`);
}
}
Workaround 2:
In this workaround, when =customFun(today()) is put to a cell, the week number is calculated by Google Apps Script and the result value is put to the cell.
Sample script:
function customFun(date) {
Date.prototype.getWeek = function() {
var onejan = new Date(this.getFullYear(), 0, 1);
return Math.ceil((((this - onejan) / 86400000) + onejan.getDay() + 1) / 7);
}
return date.getWeek();
}
getWeek() is from https://stackoverflow.com/a/7765814/7108653.
References:
Custom Functions in Google Sheets
Simple Triggers
Whenever I attempt to display a UI dialog (e.g. msgBox or alert) it works fine when invoked via a menu item (e.g. from Google Sheets), but it hangs my script if I try to invoke it from the Google Apps Script editor (e.g. via Run > Run function).
My guess is it's because the Google Apps Script editor can't display any UI. To resolve this, I'd like to create a wrapper function that checks how the script was run, and not present UI depending on the source.
The "Executions" screen has the notion of Type (Editor, Standalone, Trigger):
This makes me think there is a way to get this type in code somehow.
Psuedo code of what the function might look like:
function showMessage(message) {
var scriptSource = ???;
if (scriptSource === "Standalone") {
Browser.msgBox(message);
} else {
console.log(message);
}
}
How would I get the scriptSource?
The closest thing I can find is TriggerSource, but that is missing the enum values 'Editor' and 'Trigger'. Furthermore, it's a property only available on a Trigger. I don't know how to access the current trigger. From my understanding, that's only available via the event object (e.g. via triggerUid) on functions acting as triggers. This method I'm running in the apps script editor doesn't have access to an event object.
Not the best solution, but my current workaround is to create 3 versions of each function, and append how it was invoked to the name.
For example, if there was a "Hello World" function:
function onOpen() {
var menu = [
{name: 'Hello World', functionName: 'helloWorldViaMenu_'},
];
SpreadsheetApp.getActive().addMenu('Custom', menu);
}
function helloWorldViaMenu_() {
helloWorld_(false);
}
function helloWorldViaEditor() {
helloWorld_(true);
}
function helloWorld_(invokedFromEditor) {
if (invokedFromEditor) {
Logger.log("Hello world");
} else {
Browser.msgBox("Hello world");
}
}
helloWorldViaEditor is the only that doesn't have a _ at the end so it can be selected via the "Select function" Editor UI dropdown.
You want to know whether the current project is the container-bound script type or the standalone script type.
You want to use Browser.msgBox().
I could understand about your question as above. In order to achieve it, as a workaround,I would like to propose to use Apps Script API. The flow of sample script is as follows. I think that there are several workarounds for your situation. So please think of this as one of them.
Retrieve the parent ID of the project using the method of projects.get in Apps Script API. The parent ID means that the file ID of Google Docs.
When the parent ID is returned, it is found that the project is the container-bound script type.
When the parent ID is NOT returned, it is found that the project is the standalone script type.
When the mimeType of parent ID is Google Form, Browser.msgBox() cannot be used. So the if statement is used for this.
Sample script:
This is a sample script. In this sample script, the script ID of current project is used. Of course, you can also manually give the script ID.
var id = ScriptApp.getScriptId(); // Retrieve scriptId of current project.
var url = "https://script.googleapis.com/v1/projects/" + id + "?fields=parentId";
var res = UrlFetchApp.fetch(url, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
res = JSON.parse(res.getContentText());
if ("parentId" in res) {
Logger.log("Container-bound script type.")
var mimeType = DriveApp.getFileById(res.parentId).getMimeType();
if (mimeType === MimeType.GOOGLE_FORMS) {
Logger.log("Browser.msgBox() cannot be used at Google Form.");
} else {
Browser.msgBox("Hello world");
}
} else {
Logger.log("Standalone script type.")
Logger.log("Hello world");
}
Note:
When you use this script, please do the following flow.
Enable Apps Script API at API console.
At least, add the following scopes to the manifests.
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/script.external_request
https://www.googleapis.com/auth/script.projects.readonly
If in your script, other scopes are required to be added, please add them. And if you want to use the automatically installer of scopes with the script editor, you can achieve it using a library. You can see the detail information at here.
References:
Apps Script API
Manifests
projects.get
Taking Advantage of Manifests by GAS Library
If I misunderstand your question, I'm sorry.
Edit:
You want to confirm whether the function is called from the script editor or the custom menu.
If my understanding is correct, how about this sample script? This is a sample script. The process list can be retrieved by giving the script ID and function name. In this sample script, using "ProcessType" of processes.listScriptProcesses in Apps Script API, it confirms whether the function is called from the script editor or the custom menu.
Sample script:
This is a sample script. The process list can be retrieved by giving the script ID and function name.
When you use this script, please enable Apps Script API at API console, and add a scope of https://www.googleapis.com/auth/script.processes to the manifests.
The how to use this script is as follows.
Run addCustomMenu().
Run sampleFunction at the custom menu.
By this, Call from custom menu is shown in log.
Run sampleFunction at the script editor.
By this, Call from script editor is shown in log.
Script:
function addCustomMenu() {
SpreadsheetApp.getUi().createMenu('sampleCustomMenu').addItem('sample', 'sampleFunction').addToUi();
}
function sampleFunction() {
var scriptId = ScriptApp.getScriptId();
var functionName = "sampleFunction";
var url = "https://script.googleapis.com/v1/processes:listScriptProcesses?scriptId=" + scriptId + "&scriptProcessFilter.functionName=" + functionName;
var res = UrlFetchApp.fetch(url, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}, muteHttpExceptions: true});
res = JSON.parse(res);
if (!("processType" in res.processes[0])) {
Logger.log("Call from custom menu")
} else if (res.processes[0].processType == "EDITOR") {
Logger.log("Call from script editor")
}
}
References:
Apps Script API
Manifests
processes.listScriptProcesses
ProcessType
Making Dialogs
You can run them from the menu or the script editor. They work the same.
function makeAmenu(){
SpreadsheetApp.getUi().createMenu('A Menu')
.addItem('Run my Dialogs', 'showMyDialogs')
.addToUi();
}
function showMyDialogs(){
var ui=SpreadsheetApp.getUi();
ui.alert('This is an alert');
ui.prompt('This is a prompt');
var html=HtmlService.createHtmlOutput('<p>This is a modeless dialog</p><input type="button" value="Close" onClick="google.script.host.close();" />');
ui.showModelessDialog(html, 'Dialog');
}
If you run a script from here:
The you have to go here to see it:
In writing a 'custom function' Google Script for my particular sheet, I simply want to hide a column:
function hideColumn(index) {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get first sheet
var sheet = ss.getSheets()[0];
sheet.hideColumns(index);
}
This code works fine when I run it from within the Script editor but if I try to run it from inside a cell "=hideColumn(2)", I get the following error:
"You do not have permission to call hideColumns (line 48)."
From the same sheet/ script I'm able to run other custom functions such as:
function metersToMiles(meters) {
if (typeof meters != 'number') {
return null;
}
return meters / 1000 * 0.621371;
}
This seems to be some issue with the hideColumns function being run from inside a sheet? (ie. custom function?)
Your script 'hideColumn' is not a custom function, but a 'normal script'. Also it does not return anything (whereas the second function does). Only custom functions can be entered like formulas in the spreadsheet. See here for more info. My advice would be to create an extra menu-item using an onOpen trigger so you can run the function from the (spreadsheet)menu.
Hope that helps ?
I know we can run the script on ONCLICK and ONEDIT....
I want to run my Google apps script when the worksheet added to my existing spreadsheet...
This script should modify some contents in the newly added sheet...
Is it possible?
If so please tell me how...
One way I've managed to do this is to define a trigger on the On Change event of the spreadsheet and call the onChange function shown below:
/* CODE FOR DEMONSTRATION PURPOSES */
function onChange(e) {
var _changeType = e.changeType, _ss = e.source, _newss;
Logger.log(_changeType);
if(_changeType === 'INSERT_GRID') {
_newss = _ss.setActiveSheet(_ss.getSheets()[_ss.getActiveSheet().getIndex()]);
Logger.clear();
Logger.log(_newss.getName());
}
}
Script-Editor: wrote a script with the onOpen-function (see below). When started with the script-editor, it works correctly. when started when the spreadsheet is opened, I get the log of stmt 31 "Logger.log(name)", nothing else happens. Why?
Here is the complete script:
function onOpen() {
n0="T22 ";
n1=n0+"aktuell"
n2=n0+"Master"
var y1=DayShift();
Browser.msgBox("Returned with "+y1);
};
function DayShift() {
var dt=Browser.inputBox("Datum (YYMMDD) eingeben");
if (dt=="cancel" || dt.length !=6) return("Input "+dt);
var f1=GetFL(n1,0);
if (f1=="cancel") return("F1 cancel");
Logger.log(f1);
var Rx=f1.getSheetByName("Sheet1").getRange("B9").getValue();
f1.rename(n0+dt);
Logger.log(Rx);
Logger.log(f1.getName()+" finished");
var f2=GetFL(n2,1);
if (f2=="cancel") return("F2 cancel");
Logger.log(f2);
f2.getSheetByName("Sheet1").getRange("B7").setValue(Rx);
Logger.log(f1.getName()+" finished");
return("OK");
};
function GetFL(name,typ) {
Logger.log(name);
var fx = DocsList.find(name);
Logger.log(name+" = "+fx.length);
if (fx.length != 1) return("cancel");
if (typ==1) {
var fy=fx[0].makeCopy(n1);
} else {
var fy=fx[0];
};
fy=SpreadsheetApp.openById(fy.getId());
Logger.log(fy);
return (fy);
};
As a complement to Jonathon's answer, you could use the installable onOpen trigger instead of the simple one. Just give this function another name to avoid confusion, for example IonOpen() or whatever... the installable triggers don't have the limitations Jonathon was mentioning.
See doc on Using Container-Specific Installable Triggers
running onOpen from the script editor treats as any other script. running it as a simple triggered function will not allow access to the DocsList API as this cannot be run anonymously. Even if you have authorised the script to run as you, simple triggers run anonymously and certain APIs will not allow this.
In this case onOpen (and onEdit) silently fail.
It won't fix this for you, but the explanation can be found in the GAS documentation.
It can be frustrating/mystifying when you first encounter this, but there are ways around it even if it means running scripts from menu commands or buttons: both confer identity of the user on the script.