Is there a work around for an object oriented front-end in Google Script - google-apps-script

I'm having some problems with an event handler in the object below. I can't remember the error message but it basically said that it could not find the function. The code below is an example of what I'm trying to do.
var anObject = function () {
var n = 0;
var HandleClick(e) {
n ++;
};
return {
Init: function () {
var app = UiApp.getActiveApplication();
var handler = app.createServerHandler("HandleClick");
var com = UiApp.LoadComponent("MyGui", {prefix: "a"});
com.getElementById("button").addClickHandler(handler);
}
}
}
Would really appreciate a work-around if possible, if that is not possible then please tell me what you would suggest because I'm not sure how best to get around this.
Thanks guys.

All handler functions must be top level functions on your script. It's not possible to have it inside an object like this.

Related

How to adding item menus with the java script of an loop's sub menus inside like this example ".addItem("Go to This Sheet", "S"+i+"GoToS")"?

Hy, Everyone .. I have a question about creating the menu in GAS (Google Apps Scripts) to implement to a Google Spreadsheet without a three of the scripts which is has been take long long way and take my energy too and many many so many lines of the scripts like this I have created. This is the script. Here's the code :
function Menu1() {
var ui = s.getUi(),
s = SpreadsheetApp,
ss = s.getAcgtiveSpreadsheet(),
sss = ss.getSheets(),
madeMenu = ui.createMenu('Sheet Tools Just For an Example Menus');
for (var i=0; i < sss.length; i++){
madeMenu.addSubMenu(ui.createMenu(sss[i].getName())
.addItem('Go to ...', 'S'+i+'GoToS')
.addItem('Rename ...', 'S'+i+'RenameS')
.addItem('Move ...', 'S'+i+'MoveS'))
madeMenu.addToUi();
}
}
function GoToS(getSheetNumber) {
var sheet = sss[getSheetNumber];
ss.setActiveSheet(sheet);
}
This of the main of my problems cames to !!! Because these structures of the scripts and then so to make me had to create this lines. See at the below :
function S0GoToS() {
GoToS(0)
}
function S1GoToS() {
GoToS(1)
}
function S2GoToS() {
GoToS(2)
}
function S3GoToS() {
GoToS(3)
}
function S4GoToS() {
GoToS(4)
}
function S5GoToS() {
GoToS(5)
}
The question is How to create them without the third-sub of the scripts ??? I thought and I hope there is the another way to create these for sure yes I believe there is but that just the because I don't know how about that way. Please someone chould be can help me to solve this case. Any achieves will be appreciated. Thanks in advance has taken in your time and I appologies for my poor english.
You can, in fact, generate those functions dynamically. The idea is to keep a for-loop outside of any of your functions, in the "global" scope, which will generate all these functions. Afterwards, they can be called by a menu action. Your could would look like the following:
// function "constructors"
function createGoToFunction(sheetIndex) {
return function() {
var sheet = SpreadsheetApp.getActive().getSheets()[sheetIndex];
sheet.activate();
}
}
function createRenameFunction(sheetIndex) {
return function() {
// Your rename logic
}
}
function createMoveFunction(sheetIndex) {
return function() {
// Your move logic
}
}
// functions definition
this['ALL_SHEETS'] = SpreadsheetApp.getActive().getSheets();
for (i=0; i<this['ALL_SHEETS'].length; i++) {
this['S'+i+'GoToS'] = createGoToFunction(i);
this['S'+i+'RenameS'] = createRenameFunction(i);
this['S'+i+'MoveS'] = createMoveFunction(i);
}
delete this['ALL_SHEETS'];
delete this['i'];
function Menu1() {
var ui = SpreadsheetApp.getUi();
var sheets = SpreadsheetApp.getActive().getSheets();
var madeMenu = ui.createMenu('Sheet Tools Just For an Example Menus');
for (var i=0; i < sheets.length; i++){
var subMenu = ui.createMenu(sheets[i].getName())
.addItem('Go to ...', 'S'+i+'GoToS')
.addItem('Rename ...', 'S'+i+'RenameS')
.addItem('Move ...', 'S'+i+'MoveS');
madeMenu.addSubMenu(subMenu);
}
madeMenu.addToUi();
}
function onOpen() {
Menu1();
}
In order to implement your own functionality for the functions, you just have to change the body of them defined on top (see createGoToFunction as an example).

how to insert an image from base64 string

The code below should insert an image blob made from the base64 string img_3k, but somehow it doesn't. What am I doing wrong?
var img_3k = "iVBORw0KGg..."
function searchAndReplace() {
var body = DocumentApp.getActiveDocument().getBody();
var blobImg = Utilities.newBlob(Utilities.base64Decode(img_3k), MimeType.PNG);
body.insertImage(0, blobImg);
}
Well, I have no problem with your code.
I guess your problem is that you use a global variable, but you can not use global variables in Google Apps Script.
function searchAndReplace() {
var img= getImage();
var body = DocumentApp.getActiveDocument().getBody();
var blobImg = Utilities.newBlob(Utilities.base64Decode(img), MimeType.PNG);
body.insertImage(0, blobImg);
}
function getImage() {
return "iVBORw0KGgoAAA...SUVORK5CYII=";
}
just remove the "var" before your global var declaration:
img_3k = "iVBORw0KGg...";
Variables declared with var in global scope won't be visible in functions.
You could capitalize the variable as well (IMG_3K) so you know immediately that it is a static global one
The code was actually correct, but didn't get executed because I didn't call it from the right place. Put in the onInstall method and then it worked.

Passing state/data to Google Apps Script ServerHandler

I am trying to work out how I can pass some arbitrary state to a ServerHandler in Google Apps Script. The following code illustrates the question - can anybody help?
Thanks.
function myFunc(e) {
// want to get my data object back out here..?
}
function setUp()
{
var data = getMyDataArray();
// ... set up UI...
var h = app.createServerHandler('myFunc');
// How do I passs my data object to the myFunc handler?
flow.add(app.createButton().setText("OK").addClickHandler(h));
app.add(flow);
s.show(app);
}
You can use Hidden elements to store arbitrary data and send it along with a server handler invocation. The issue is that the the element can only store a string. But you can solve this using JSON.
function myFunc(e) {
var yourObj = Utilities.jsonParse(e.parameter.yourObject);
//do what you need
}
function setUp()
{
var data = getMyDataArray();
// ... set up UI...
var hidden = app.createHidden("yourObject", Utilities.jsonStringify(data));
var h = app.createServerHandler('myFunc').addCallbackElement(hidden);
flow.add(app.createButton().setText("OK").addClickHandler(h));
app.add(flow);
s.show(app);
}

Google Apps Script, HTML addClickHandler ServerHandler does NOT work

Can anyone confirm that HTML widgets accept ClickHandlers on the Server side ? I can't get my below code to work.
I create a serverHandler (and for good measure I have even added a useless callback element). Subsequently, I add it to a HTML.addClickHander (for good measure I have even added it to .addMouseUpHandler as well). The function is NOT executed.
var mouseclick = app.createServerHandler("handleTrainingClick_").addCallbackElement(lstFilter);
var params = [ "fromOrg", "trainingTitle", "dueDate", "medical", "status" ];
var resultSet = blSelectActiveTrainings_();
while (resultSet.hasNext()) {
var training = resultSet.next();
var html = TRAINING_ROW;
for (var pI in params) {
html = html.replace("$"+params[pI], training[params[pI]]);
}
pnlList.add(app.createHTML(html).setId(training.id).addClickHandler(mouseclick).addMouseUpHandler(mouseclick)
.addMouseMoveHandler(mousemove).addMouseOutHandler(mouseout).addMouseOverHandler(mouseover));
}
function handleTrainingClick_(e) {
Logger.log(e.source);
var app = UiApp.getActiveApplication();
return app;
}
HTML widgets server side handlers work just fine. It was an incorrect reference in my code. Thanks all.

AS3 Passing Variable Parameters to a generic Function Menu / SubItems

I'm no code genius, but a fan of action script.
Can you help me on this:
I have a function that depending on the object selected, will call event listeners to a set of 'sub-items' that are already on stage (I want to reuse this subitems with changed parameters upon click, instead of creating several instances and several code).
So for each selected 'case' I have to pass diferent variables to those 'sub-items', like this:
function fooMenu(event:MouseEvent):void {
switch (event.currentTarget.name)
{
case "btUa1" :
trace(event.currentTarget.name);
// a bunch of code goes here
//(just cleaned to easy the view)
/*
HELP HERE <--
here is a way to pass the variables to those subitems
*/
break;
}
}
function fooSub(event:MouseEvent):void
{
trace(event.target.data);
trace(event.currentTarget.name);
// HELP PLEASE <-> How can I access the variables that I need here ?
}
btUa1.addEventListener(MouseEvent.CLICK, fooMenu);
btUa2.addEventListener(MouseEvent.CLICK, fooMenu);
btTextos.addEventListener(MouseEvent.CLICK, fooSub);
btLegislacao.addEventListener(MouseEvent.CLICK, fooSub);
Anyone to help me please?
Thank very much in advance. :)
(I'm not sure I got your question right, and I haven't developed in AS3 for a while.)
If you want to simply create function with parameters which will be called upon a click (or other event) you can simply use this:
btUa1.addEventListener(MouseEvent.CLICK, function() {
fooMenu(parameters);
});
btUa2.addEventListener(MouseEvent.CLICK, function() {
fooMenu(other_parameters)
}):
public function fooMenu(...rest):void {
for(var i:uint = 0; i < rest.length; i++)
{
// creating elements
}
}
If you want to call event listeners assigned to something else you can use DispatchEvent
btnTextos.dispatchEvent(new MouseEvent(MouseEvent.CLICK))
Remember, you can't use btTextos.addEventListener(MouseEvent.CLICK, carregaConteudo("jocasta")); because the 2nd parameter you pass while adding Eventlistener will be considered as function itself - there are two proper ways to use addEventListener:
1:
function doSomething(event:MouseEvent):void
{
// function code
}
element.addEventListener(MouseEvent.CLICK, doSomething); //notice no brackets
2:
element.addEventListener(MouseEvent.CLICK, function() { // function code });
So:
function fooSub(event:MouseEvent, bla:String):void
{
trace(event.currentTarget.name+" - "+bla);
// bla would be a clip name.
}
codebtTextos.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) { fooSub(e, "jocasta") } );
Or try something like this if you want content to be dynamically generated:
btUa1.addEventListener(MouseEvent.CLICK, function() {
createMenu(1);
});
btUa2.addEventListener(MouseEvent.CLICK, function() {
createMenu(2);
});
function createMenu(id):void
{
// Switching submenu elements
switch (id)
{
case 1:
createSubmenu([myFunc1, myFunc2, myFunc3]); // dynamically creating submenus in case you need more of them than u already have
break;
case 2:
createSubmenu([myFunc4, myFunc5, myFunc6, myFunc7]);
break;
default:
[ and so on ..]
}
}
function createSubmenu(...rest):void {
for (var i:uint = 0; i < rest.length; i++)
{
var mc:SubItem = new SubItem(); // Subitem should be an MovieClip in library exported for ActionScript
mc.addEventListener(MouseEvent.CLICK, rest[i] as function)
mc.x = i * 100;
mc.y = 0;
this.addChild(mc);
}
}
Your question is rather vague; what "variables" do you want to "pass"? And what do you mean by "passing the variable to a sub item"? Usually "passing" means invoking a function.
If you can be more specific on what exactly your trying to do that would be helpful. In the meantime, here are three things that may get at what you want:
You can get any member of any object using bracket notation.
var mc:MovieClip = someMovieClip;
var xVal:Number = mc.x; // The obvious way
xVal = mc["x"]; // This works too
var propName:String = "x";
xVal = mc[propName] ; // So does this.
You can refer to functions using variables
function echo(message:String):void {
trace(message);
}
echo("Hello"); // The normal way
var f:Function = echo;
f("Hello"); // This also works
You can call a function with all the arguments in an array using function.apply
// Extending the above example...
var fArgs:Array = ["Hello"];
f.apply(fArgs); // This does the same thing
Between these three things (and the rest parameter noted by another poster) you can write some very flexible code. Dynamic code comes at a performance cost for sure, but as long as the frequency of calls is a few hundred times per second or less you'll never notice the difference.