I've created a GUI (MyGui) with a flow panel (mainPanel), a text box (textValue) and a button (getETA). All in a sites script.
The idea is that a value is entered in the text box, the button is clicked and the value is then placed in the cell A1 of a spreadsheet.
There is no handler configured in the GUI and I've copy pasted the script to a fresh site, no success though.
The problem I'm having is that all I get in the spreadsheet cell is "undefined".
Also if I run a debug on the clickGetETA function I get the following error message: "Cannot read property "parameter" from undefined"
I'm new to this but my best guess is that the details of the GUI are not being passed on to the clickGetETA function. I've searched what I can but I can't appear to find a solution...
If someone could tell me where I'm going wrong I'd appreciate he help.
function doGet() {
var app= UiApp.createApplication();
app.add(app.loadComponent("MyGui"));
var clickHandler = app.createServerHandler('clickGetETA');
clickHandler.addCallbackElement(app.getElementById('mainPanel'));
app.getElementById('getETA').addClickHandler(clickHandler);
return app;
}
function clickGetETA(e) {
var sheet = SpreadsheetApp.openById('abcdefghjklmnopqrstuvwxyz');
var ss = sheet.getActiveSheet();
var target = ss.setActiveCell("A1");
target.setValue(e.parameter.textValue);
}
Change:
var ss = sheet.getActiveSheet();
var target = ss.setActiveCell("A1");
To :
var ss = sheet.getSheetByName("SheetName");
var target = ss.getRange("A1");
Good examples for this kind of thing are here:
https://developers.google.com/apps-script/guide_user_interfaces
It should be run as a service. i.e. you use the get function.
Notes: the "e" parameter does not exist when you debug. Debugging is a little limited.
ActiveSheet and ActiveCell are designed to be used from a spreadsheet not a service.
A service creates a web page rather than a popup box.
Eddy.
The callback element used in the addCallbackElement may be a single widget or the a panel of your GUI. When passing a panel, all widgets bellow in the panel hierarchy will be included in the parameter. Are you sure your textbox is inside the panel you're adding?
Also, the values of the widgets can be accessed in the handler function using the widget name (that you must set on the GUI builder). Notice the difference between name and id, the id you use to get the widget using getElementById and also to determine the widget source of the events, when you use the same handler for multiple widgets. And the name for accessing the value. Are you sure you named your textbox as textValue?
What fixed it for me was going into the UI editor and making sure I had an ID assigned for form fields and a name. I was missing the name so my e.parameter.fieldName was undefined.
Related
if I have a simple code like below and I break after this line
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
I will see the variable sheet in the debugger. If I expand it, I will see many functions such as getName. If I expand getName, I will see information such as name: "".
I was expecting to see the name of the activeSheet but it was not there. What are these information for and how can I use them in debugging?
I just want to make sure there isn't a better way to debug and I do not know.
Sheet.getName is a function object, and Google has chosen to not reveal the implementation of these methods. The name property of the function would contain the function's name rather than the name of the active sheet, but my recollection is that the V8 engine used by Google Apps Script does not reveal function names through that property in the debugger.
To see the sheet name in the debugger, declare another variable, like this:
const sheetName = sheet.getName();
Since I tend to ramble, first a short version and if you need more information read the long one.
TL;DR
Why is this:
function doGet(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var jobsCreated = sheet.getRange(12,2).getValue();
Browser.msgBox(jobsCreated);
var params = JSON.stringify({number:jobsCreated});
return ContentService.createTextOutput(params);
}
returning this when I published as website and then open:
{"number":""}
when it should look more like this {"number":2451}
Full Version:
First of all, I learned to program back in uni for my Computer science degree (10 years ago) but since then I haven't done much programming so I am basically a newbie.
Now to the question. I have a very simple script that a created with the script editor from Google Sheets
function doGet(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var jobsCreated = sheet.getRange(12,2).getValue();
Browser.msgBox(jobsCreated);
var params = JSON.stringify({number:jobsCreated});
return ContentService.createTextOutput(params);
}
First I get the sheet I am working on
Then I select a cell from that sheet
now if I use a msgBox to make sure that I have the right number and run the script, it works and it shows the message.
next, I format the variable as JSON and finally I just create a text output.
Now I deploy as Web app
Execute as ME
Anyone, even anonymous
And when I access the website I can only see this:
{"number":""}
If I change the code and give jobsCreated and static value it works fine
var jobsCreated = 100;
{"number":100}
So my conclusion is that the problem is with accessing the value of the cell when running the script from the published link compare to running it directly from the editor, but I have no idea how to fix this.
A little bit more information, i am trying to use this for a counter called Smiirl, i got most of the information from here
https://medium.com/#m_nebra/bootstrapping-your-company-counter-22f5d4bc7dd4
try this:
function doGet(e) {
return ContentService.createTextOutput(Utilities.formatString('number: %s',SpreadsheetApp.getActiveSheet().getRange(12,2).getValue());
}
Ok as I replied to #Aerials, thank you again for your help btw. Seeing other codes that should work not working with my script, I decided to create a new sheet and script as a test and with the exact same code it works.
But now checking on it a little bit more, something that I didn't think it was a problem since it was getting the number without any problems. The cell it's being populated by a GoogleAnalytics add-on. Now when setting up the add-on again to get the information the script from the website returns an empty value again. SO it seems the issue is with the script getting the information from the sheet (only the published version) when its being populated by the add on
Your issue is in the use of JSON.stringify
In JSON, functions are not allowed as object values.
The JSON.stringify() function will omit or change to null any functions from a JavaScript object.
That said, you can do the following:
function doGet(e){
// Get the value of the range
var sheet = SpreadsheetApp.getActiveSheet();
var jobsCreated = sheet.getRange(12,2).getValue();
// JSON Stringify it
var params = JSON.stringify({"number" : number=jobsCreated});
// Return JSON string
return ContentService.createTextOutput(params);
}
Returns:
{"number":123} if jobsCreated is the number 123, or
{"number":"Mangos"} if jobsCreated is the string "Mangos".
See it the script deployed here, and the sheet to play with.
Note:
You should avoid using functions in JSON, the functions will lose their scope, and you would have to use eval() to convert them back into functions.
I would like to open filter views via button. If I understood it correctly, this should be possible by now. But I'm not sure, because I don't understand the whole communication on the following topic:
https://issuetracker.google.com/issues/36753410)
I have written the following code. When I execute this code, I always get the error: "Method getFilter(object) not found". What
What am I doing wrong?
function OpenFilter(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Name of the sheet'); //The sheet in which I want to open the filter view
var rg = sheet.getRange("S1:S2"); //There is the range where my Hyperlink is placed
var link = rg.getCell(1,1).getValues(); // The cell of the Hyperlink to test
var filter = sheet.getFilter(link);
SpreadsheetApp.setFilter(filter);
}
Unfortunately the method setFilter(filter) has not been implemented so far.
Also, the method getFilter() does not accept parameters, see here.
I recommend you to have a look here to find examples what you can do with filters at current stage.
Keep in mind that you need to combine SpreadsheetApp with the Advanced Sheets Service to achieve your goal.
I am trying to use a client handler to validate an entry to make sure that the entry is indeed a number. So if an entry contains a letter, for example, then I want to disable a button so that a user cannot proceed. I have built a GUI using the GUI builder, but the client handler, specifically validateNotNumber, does not work if called from the GUI.
So far for a text box I am trying to get the validator to work in, I have in the GUI builder with the ID (Base) = Name (Input Fields), for the Events section I have the "on Key Press" filled in with the name of the function that has the client handler and the name of the form the text box resides on (in my case, AbsolutePanel1).
The function called is:
function isitnotnumbers(e) {
var app = UiApp.getActiveApplication();
app.createClientHandler().validateNotNumber(app.getElementById('ThisOdometer'))
.forTargets(app.getElementById('ButtonCalcMPG')).setEnabled(false);
return app;
};
The function is indeed called I have tested it by having a message displayed when a key is press in the text box. But the button specified is not disabled as it should when a non-number key is pressed.
The examples I found listed the validators in hand coded UI widgets, so I am not sure where I am going wrong when using the GUI builder.
So, where did I go wrong and how can I fix this?
Is there a work around if the GUI builder does have limitations with client handlers (such as using the HTML service)?
My other attempt(s):
I have tried to add a click handler to the text box, which is a modification to the code above:
var app = UiApp.getActiveApplication();
var handlernumbers = app.createClientHandler()
.forTargets(app.getElementById('LabelUserMessage'))
.setText('THe message');
var odobox = app.getElementById('ThisOdometer');
odobox.addClickHandler(handlernumbers);
return app;
Try this:
function isitnotnumbers(e) {
var app = UiApp.getActiveApplication();
app.getElementById('ThisOdometer').addKeyUpHandler(app.createClientHandler().validateNotNumber(app.getElementById('ThisOdometer'))
.forTargets(app.getElementById('ButtonCalcMPG')).setEnabled(false));
return app;
};
Edit:
You don't need this code in a separate function, just add the following line to your doGet() or in the main function (so that the handler is created only once when the app launches):
app.getElementById('ThisOdometer').addKeyUpHandler(app.createClientHandler().validateNotNumber(app.getElementById('ThisOdometer'))
.forTargets(app.getElementById('ButtonCalcMPG')).setEnabled(false));
To answer my own question, I will say that it does not matter as google is deprecating gui builder, and will cease to function after September.
I should, or perhaps I should have started to, learn uiservice or htmlservice.
I'd like a little sanity check if I may.
Can Javascript code in an HtmlOutput window floated over a Google spreadsheet alter variables and call methods in the gs code that created the HtmlOutput in the first place?
I have a Google spreadsheet with a floating form created like this:
someCode.gs
var theForm;
var theSpreadsheet;
function makeForm() {
:
theForm = HtmlService.createTemplateFromFile('aForm').evaluate();
theSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
theSpreadsheet.show(theForm);
:
}
function recordTheForm(jsonFormData) {
:
theForm.clear();
:
}
Attached to a button in the HTML of "aForm.html" I have a function call back into the file "someCode.gs".
aForm.html
:
google.script.run.recordTheForm(jsonTheForm);
:
Am I right that, even though it was instantiated from someCode.gs, the caller of recordTheForm() can have no knowledge of the contents of that originating memory space?
Is there anyway to get it? such as passing a "context" back and forth?
Variables in GAS:
Browser button clicks and other browser events produce a call to GAS. Every call from the browser to GAS causes your GAS code to re-run, re-initializing all variables. This is a problem for global variables. Global variables need to be passed back from the Browser to your GAS code or reloaded from the Database or Script Properties.