1

What is the easiest way to get some kind of toggle switch for Google HtmlService?

Google UiApp used to be able to create a simple ToggleButton like the following:

var toggleButton = app.createToggleButton('ON', 'Off').setId('MySwitch');

But UiApp has been deprecated. "Please use HtmlService instead"

I've tried

But found I cannot make them a two-stage item. Then I tried

and was able to get the HTML part working, but moving it to Google HtmlService, I cannot make it work no matter what.

Can someone give me a working Google HtmlService example that contains a two-stage item that I can use to control my output please.

UPDATE:

Thanks a lot @MetaMan for your excellent example, I tried hard to come up with the smallest example, but I'll never be able to get the level of your code, so compact and elegant!

Just one thing, I haven't been able to make it work yet. I'm getting ReferenceError: gobj is not defined.

enter image description here

I then changed them into plain text, as

enter image description here

But got Execution completed without seeing the dialog. How can I make it works?

UPDATE2:

Ops, dialog showed up after a while. Thanks @MetaMan, I'll ask the following in a separated question --

One more thing, @MetaMan, In the HTML demo code that I provided, I was able to make use of form.myButton.value, but the problem is when I try to use that to update my label from within Google App Code function, just as what the HTML demo code is doning, it always fails and I don't know why. Do you have a quick answer for that, or you'd rather me asking in a separated question?

thx

xpt
  • 20,363
  • 37
  • 127
  • 216

1 Answers1

2

Here's a toggle function that presents a dialog that has a button that turns a light on and off:

function launchLightToggleDialog() {
  let html='';
  html += '<html><head></head><body>';
  html += '<br /><img id="light" src="" />';
  html += '<br /><input type="button" id="btn" value="Toggle" onclick="toggle()" />&nbsp;&nbsp;<label id="lbl" for="btn"></label>';
  html += '<script>';
  html += 'var light="on";'  
  html += 'var lighton = <?= getMyDataURI(gobj.globals.lightonid) ?>;\n';
  html += 'var lightoff = <?= getMyDataURI(gobj.globals.lightoffid) ?>;\n';
  html += 'window.onload=function(){document.getElementById("light").src=(light=="on")?lighton:lightoff;document.getElementById("lbl").innerHTML=light;}\n';

  html += 'function toggle(){light = (light=="on")?"off":"on";document.getElementById("light").src=(light=="on")?lighton:lightoff;document.getElementById("lbl").innerHTML=light;}\n';
  html += 'console.log("mycode");\n'
  html += '</script>';
  html += '</body></html>';
  let t=HtmlService.createTemplate(html);
  let o=t.evaluate();//The dataURI's get loaded here
  SpreadsheetApp.getUi().showModelessDialog(o,"Light Toggle");
}

The below function just opens up the files where I store the dataURI's of the lighton and lightoff images and it returns the dataURI's as strings for use in the webapp. Making it possible for me to serve the images off of my Google Drive.

function getMyDataURI(fileId) {
  const file=DriveApp.getFileById(fileId);
  return file.getBlob().getDataAsString();
}

Demo:

enter image description here

Both functions are Google Apps Script and all JavaScript functions are imbedded in the html string.

If you wish to convert an image to a dataURI:

function convImageUrl(url){
  var url=url || "default url";
  var blob=UrlFetchApp.fetch(url).getBlob();
  var b64Url='data:' + blob.getContentType() + ';base64,' + Utilities.base64Encode(blob.getBytes());
  return b64Url;
}

function saveDataURIInFile(filename,datauri,type) {
  Logger.log('filename: %s\ndatauri: %s\ntype: %s\n',filename,datauri,type);
  if(filename && datauri && type) {
    var folder=DriveApp.getFolderById(getGlobal('MediaFolderId'));
    var files=folder.getFilesByName(filename);
    while(files.hasNext()) {
      files.next().setTrashed(true);
    }
    var f=folder.createFile(filename,datauri,MimeType.PLAIN_TEXT);
    return {name:f.getName(),id:f.getId(),type:type,uri:DriveApp.getFileById(f.getId()).getBlob().getDataAsString()};
  }else{
    throw('Invalid input in saveDataURIInFile.');
  }
}
Cooper
  • 59,616
  • 6
  • 23
  • 54
  • How to define the `globals.lightonid` please? – xpt Apr 27 '21 at 12:30
  • It’s just the id of the file where you store your data URI – Cooper Apr 27 '21 at 14:13
  • I meant, if I want to get my script in the first screenshot to work, where should I put/define those two global variables? I did tried to search on the KW of "gobj.globals", but the top two hits, https://stackoverflow.com/questions/65150194/, https://stackoverflow.com/questions/11168623/, still didn't give me much clue. However, I will not hold off any more and am giving you all the credit you deserve, but only letting you know that there is still one piece missing I wasn't able to solve myself. thx again. – xpt Apr 28 '21 at 04:09
  • If I were you and I didn't know how to use global variables then I would just be replace them with their values. – Cooper Apr 28 '21 at 15:54
  • `gobj.globals.lightonid` is a file id so just replace with the file id for the dataURI. And the last two functions can be used to create a dataURI. You can copy images to your Photos Library and then view them and get their url and use that url to create the dataURI and then copy the dataURI and paste it into a file or use the function that I gave you. You will need two file one for on and one for off. Replace the global variables with those fileIds. – Cooper Apr 28 '21 at 16:01
  • Got it, that's exactly what I did. Ok, seems global variables is quite a strange beast, https://stackoverflow.com/questions/24721226/, I'll stay away from it :). – xpt Apr 29 '21 at 00:13
  • 1
    I store my global variable in sheet that I call globals and I also store some of them in PropertiesService. And I use a technique called lazy loading to load them every time I run a function on the server. It's not something I'd do for a production environment but for writing independ scripts for SO it works just fine and saves me from having to redact the final script very much. – Cooper Apr 29 '21 at 01:55