I am trying to create an app script for a Google Spreadsheet that I have. I created a script for another sheet a couple of years ago and I can't remember how to to get the component ID.
Here's the code:
var pointsSheet = SpreadsheetApp.openById('1o8_f063j1jYZjFEnI_P7uAztpnEAvQ6mc3Z1_Owa69Y');
function doGet() {
var app = UiApp.createApplication();
app.add(app.loadComponent("Marks")); //IT IS NOT CALLED MARKS!
var panel = app.getElementById("VerticalPanel1");
var text = app.createPasswordTextBox().setName("text");
var handler = app.createServerHandler("getResults").addCallbackElement(text);
panel.add(text);
panel.add(app.createButton("Get Record", handler));
//SpreadsheetApp.getActiveSpreadsheet().show(app);
return app;
}
...
The commented part where it says "IT IS NOT CALLED MARKS" is the part I'm talking about. In my other script this works, but in the new script it doesn't work. How do I find the component name (if that's what it's called)?
You are trying to run a script that uses the GUI Builder, a couple of years ago it was possible but now it is not anymore (since october 2013)! See here.
I saw that because you are using app.loadComponent("Marks"), which was the method to call the Ui components created in the GUI Builder.
The old apps built with it still work but you can't create/modify it.
EDIT following your comment :
You will have to build your UI from scratch using either UiApp - which uses the same elements as the GUI builder and the same syntax - or HTML Service.
The latter is much more powerfull but uses a completely different approach as it uses client JavaScript in combination with server code. Take a look at the docs and tutos and make your choice ;-)
Related
I'm having trouble with the autocomplete feature in Google App Script.
Built-in methods like SpreadsheetApp. will provide an autocomplete menu with methods to choose from.
However, if I create my own child object, autocomplete works for a little while, and then it just stops working.
for example:
var skywardRoster = SpreadsheetApp.getActiveSheet();
skywardRoster. will produce method options for a while, and then it stops.
However, the code still functions, and methods work if I type them out manually, so I know the declarations must be right. The menu simply won't appear, and it's just very inconvenient to have to look up each method individually as I go.
I have tried: breaking the variable and retyping that line; copy and pasting the code back into the editor; using different browsers; copying the gs file itself and working within the copy; and signing out completely and signing back in. Nothing seems to get it back to work.
I'm really new to coding, and I'm not sure what can be causing this.
Does anyone know how to fix this issue?
You might want to check Built-in Google Services:Using autocomplete:
The script editor provides a "content assist" feature, more commonly called "autocomplete," which reveals the global objects as well as methods and enums that are valid in the script's current context. To show autocomplete suggestions, select the menu item Edit > Content assist or press Ctrl+Space. Autocomplete suggestions also appear automatically whenever you type a period after a global object, enum, or method call that returns an Apps Script class. For example:
If you click on a blank line in the script editor and activate autocomplete, you will see a list of the global objects.
If you type the full name of a global object or select one from autocomplete, then type . (a period), you will see all methods and enums for that class.
If you type a few characters and activate autocomplete, you will see all valid suggestions that begin with those characters.
Since this was the first result on google for a non-working google script autocompletion, I will post my solution here as it maybe helps someone in the future.
The autocompletion stopped working for me when I assigned a value to a variable for a second time.
Example:
var cell = tableRow.appendTableCell();
...
cell = tableRow.appendTableCell();
So maybe create a new variable for the second assignment just during the implementation so that autocompletion works correctly. When you are done with the implementation you can replace it with the original variable.
Example:
var cell = tableRow.appendTableCell();
...
var replaceMeCell = tableRow.appendTableCell(); // new variable during the implementation
And when the implementation is done:
var cell = tableRow.appendTableCell();
...
cell = tableRow.appendTableCell(); // replace the newly created variable with the original one when you are done
Hope this helps!
I was looking for a way how to improve Google Apps Script development experience. Sometimes autocomplete misses context. For example for Google Spreadsheet trigger event parameters. I solved the problem by using clasp and #ts-check.
clasp allows to edit sources in VS Code on local machine. It can pull and push Google Apps Script code. Here is an article how to try it.
When you move to VS Code and setup environment you can add //#ts-check in the beginning of the JavaScript file to help autocomplete with the special instructions. Here is the instructions set.
My trigger example looks like this (notice autocompletion works only in VS Code, Google Apps Script cloud editor doesn't understand #ts-check instruction):
//#ts-check
/**
* #param {GoogleAppsScript.Events.SheetsOnEdit} e
*/
function onEditTrigger(e) {
var spreadsheet = e.source;
var activeSheet = spreadsheet.getActiveSheet();
Logger.log(e.value);
}
I agree, Google Script's autocomplete feature is pretty poor comparing with most of other implementations. However the lack is uderstandable in most cases and sometimes the function can be preserved.
Loosing context
The autocomplete is limited to Google objects (Spreasheets, Files, etc.). When working with them you get autocomplete hints, unless you pass such object instance to function as an argument. The context is lost then and the editor will not give you suggestions inside the called function. That is because js doesn't have type control.
You can pass an id into the function instead of the object (not File instance but fileId) and get the instance inside of the function but in most cases such operation will slow the script.
Better solution by Cameron Roberts
Cameron Roberts came with something what could be Goole's intence or a kind of hack, don't know. At the beginning of a function assign an proper object instance to parameter wariable and comment it to block:
function logFileChange(sheet, fileId){
/*
sheet = SpreadsheetApp.getActiveSheet();
*/
sheet.appendRow([fileId]); // auto completion works here
}
Auto completion preserved
I am creating some google app scripts for my company to use to generate random tests for employee training. I already have the basic scripts written to grab a list of questions from a google sheet, randomize them, grab the first 10 questions, etc. That all works fine. I decided it might be better to re-do the whole thing using a UiApp instead of just separate scripts. That is where the problem comes in. I did a simple bare bones UiApp to test with, published it and tried to hit the URL and that's where I encounter this error. I searched for this error and all I could find was some discussion about this being part of google apps premiere(which should have been folded into regular google apps around 2010). I've been staring at this so long I've frustrated myself. It should be something very simple and yet it's refusing to work. I'm assuming I am doing something wrong at a basic level but I've reached the point where my brain refuses to see it.
Here is the basic script I started with:
function doGet(e) {
var app = UiApp.createApplication();
var mainPanel = app.createVerticalPanel().setId('mainPanel');
mainPanel.add(app.createLabel('test'));
return app;
}
I save it, publish it and go to the URL and that's when I get the above error message. I know it's something simple but I've reached the point of frustration and simply can't see it.
Update: to reflect comments
Another possibility for WebApps not updating is not publishing a new version and only checking the exec URL. For instant changes to the code, always check the dev URL. The exec will only change after saving a version in Manage Versions and re-publishing the app.
First Answer:
I think your question title says it all.
UIApp is not defined, but Class is UiApp. JS is case sensitive. I copied and pasted the code exactly as it is in your question and received no errors. I did have to add one line to make the label show up.
function doGet(e) {
var app = UiApp.createApplication();
var mainPanel = app.createVerticalPanel().setId('mainPanel');
mainPanel.add(app.createLabel('test'));
app.add(mainPanel); // <-- I added this line to see the label
return app;
}
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'm trying to use the PivotCharts library that is recommended in on the apps developer site here: https://developers.google.com/apps-script/notable-script-libraries - but when I try replicating the example code:
function createReport(){
var app = UiApp.createApplication().setWidth(700).setHeight(450).setTitle('My report');
var data = SpreadsheetApp.openById('0AnxR7WfXrj7adFRnVEFTQ2NldGJodUtCZDF2U0hVNUE').getSheets() [0].getDataRange().getValues();
var panel = PivotChartsLib.createColumnChart(data, 3, 4);
app.add(panel);
SpreadsheetApp.getActiveSpreadsheet().show(app);
}
The initial chart loads, but when you try to pivot you get an error "Type Error: can not call method "apply" of undefined"
I've tested on different computers, so I think it is an issue with the library itself. I'm not sure how to access that code though to try and fix it.
I saw same error.
then i copied code from PivotCarts library,
it worked fine.
it seems pivot charts library ui need apply function,
that should be global scope function , but PivotCharts's apply function scope is into PivotCharts object.
I'm making standalone web app in Google Apps Script. I have somekind of task flow in the app. First search something from spreadsheet, then do some selections what to do with the collected data and after that fill spreadsheet row with some userinputs. So I need to run between few states.
I'm fairly sure I don't know enough about web tech so this might be very stupid question but here it goes.
I know that the e.parameters comes from the url like this www.google.com&value=helloworld
, e.parameters.value returns helloworld.
So now the problem: How do I set parameter e values in doGet(e) and call this same page or even different page/script in same script project? In otherwords how do I call self&value=helloworld ?
Is there some other way to do this? In GWT I just store everything to database and keep session in cookies. But cookies are not allowed so how to keep the state of the webapp in google apps script?
EDIT: This is how I pass the parameters for doGet(e).
function doGet(e) {
var app = UiApp.createApplication();
var newValue = 0;
if(e.parameter == undefined || e.parameter.value == undefined){
newValue = 1;
}else{
newValue = 1+parseInt(e.parameter.value);
}
var link = 'https://script.google.com/a/macros/domain.com/s/<insertidhere>/dev';
var anchor = app.createAnchor('Next',link+'?&value='+newValue);
anchor.setTarget('_self');
app.add(anchor);
var label = app.createLabel(newValue);
app.add(label);
return app;
}
The link format has changed a bit so instead of concatenate &value=... you need to add ? first like this ?&value1=helloworld&value2=....
Failing to use ? led me to think that there is bug and I need to use old format for the link and using that old format forbit any other than the script owner using it.
Hopefully this helps somebody to solve similar problems.
You've almost answered yourself. Append the URL paramenters to the end of your web app's URL and you can access them in your script.
Let's say you have a URL like
http://script.google.com/.../exec
When you hit the URL
http://script.google.com/.../exec?value=helloworld
,
inside doGet, you can read these URL parameters as
e.parameter.value;
IMO - instead of using ? to separate multiple parameters try keeping all the values in a single anchor with some other character separator of your choice such as # since after the first ? its possibly ignoring the other one and everything afterwards. Would be great to hear back on what you find.