google script unable to update web page - google-apps-script

Below is snippet where I create a web page / app and show a list. Then on click of item in list I want to replace the list with another list. I try it by using vertical panel as root container and clearing and adding list to it. The web page though keeps showing old list even after handler for new list executes fine.
//user_list function updates vertical panel but the web page still shows old rep_list
function doGet(e) {
if(e == null || e.parameter.dvid == null) {
return rep_list();
}
}
function user_list(path) {
var app = UiApp.getActiveApplication().setTitle("List Folders");
var content = app.getElementById('root');
content.clear();
var list = app.createListBox();
//populate list
content.add(list);
return app;
}
function rep_list () {
var app = UiApp.createApplication().setTitle("List Repositories");
var content = app.createVerticalPanel().setId('root');
var list = app.createListBox(true).setId('repoList').setName('repo');
var handler = app.createServerHandler("listFolders");
list.addClickHandler(handler)
//populate list
content.add(list);
app.add(content);
return app;
}
function listFolders(e){
var repo = e.parameter.repo;
user_list(repo);
}
Regards,
Miten.

Your listFolders() function isn't returning a new UI instance. Try:
function listFolders(e){
var repo = e.parameter.repo;
var app = user_list(repo);
return app;
}

Related

How to build dynamic dropdowns in configuration setup?

I'm new to Google Data Studio and looking into building a community connector for our Saas service.
For the configuration section, I need to use the Stepped Configuration process. Basically, I nested set of drop-down lists.
However, I need the data to populate those lists to come from my API. I have the REST service endpoints defined, but I cannot find any documenation/examples of how I'd configure this in the getConfig section of the community connector.
Does anyone have a working example I could use as reference?
In reviewing the documentation, there is a section on stepped configurations, which is what I am looking for. You can find that example here: https://developers.google.com/datastudio/connector/stepped-configuration#dynamic_dropdowns
In this example, they show the following for defining the dropdown values.
Notice for the states, they have hard-coded the values for "Illinois" and "California".
My question is, how can I dynamically call API to retrieve values to populate this list? I have 3 nested dropdowns, each with a separate API call, using the answer from previous dropdown to drive the next.
For example first API might be http://myapi.com/countries which returns list of countries.
When they select country, next API call might be http://myapi.com/states?country=US
etc.
config.newSelectSingle()
.setId("state")
.setName("State")
// Set isDynamic to true so any changes to State will clear the city
// selections.
.setIsDynamic(true)
.addOption(config.newOptionBuilder().setLabel("Illinois").setValue("IL"))
.addOption(config.newOptionBuilder().setLabel("California").setValue("CA"));
if (!isFirstRequest) {
var city = config.newSelectSingle()
.setId("city")
.setName("City");
var cityOptions = optionsForState(configParams.state);
cityOptions.forEach(function(labelAndValue) {
var cityLabel = labelAndValue[0];
var cityValue = labelAndValue[1];
city.addOption(config.newOptionBuilder().setLabel(cityLabel).setValue(cityValue));
});
}
return config.build();
}
Worked through the issues I was having. For others who might have hit similiar issues, here's my working getConfig() method.
function getConfig(request) {
var config = cc.getConfig();
var configParams = request.configParams;
var isFirstRequest = configParams === undefined;
if (configParams ===undefined || configParams.tab ===undefined) {
config.setIsSteppedConfig(true);
}
var url ='https://<yourAPIURL>';
var userProperties = PropertiesService.getUserProperties();
var key = userProperties.getProperty('dscc.key');
var mykey ="Bearer " + key
var options = {
"method" : "GET",
"headers" : {
"AUTHORIZATION" : mykey,
"cache-control": "no-cache"
}
};
var response = UrlFetchApp.fetch(url,options);
var parsedResponse = JSON.parse(response);
var zoneControl = config.newSelectSingle()
.setId("zone")
.setName("Zone")
.setIsDynamic(true);
parsedResponse.map(function(itm) {
zoneControl.addOption(config.newOptionBuilder().setLabel(itm.name).setValue(itm.id))
});
if(configParams !==undefined && configParams.zone !==undefined){
var blockurl ='https://<yourAPIURL>?zoneid='+ configParams.zone;
var blockResponse = UrlFetchApp.fetch(blockurl,options);
var parsedBlockResponse = JSON.parse(blockResponse);
var blockControl = config.newSelectSingle()
.setId("block")
.setName("Block")
.setIsDynamic(true);
parsedBlockResponse.map(function(itm) {
blockControl.addOption(config.newOptionBuilder().setLabel(itm.name).setValue(itm.blockKey))
});
}
if(configParams !==undefined && configParams.block !==undefined){
var taburl =''https://<yourAPIURL>?blockKey='+ configParams.block;
var tabResponse = UrlFetchApp.fetch(taburl,options);
var parsedTabResponse = JSON.parse(tabResponse);
var tabControl = config.newSelectSingle()
.setId("tab")
.setName("Tab")
parsedTabResponse.map(function(itm) {
tabControl.addOption(config.newOptionBuilder().setLabel(itm.name).setValue(itm.internalname))
});
}
return config.build();
}
without testing the code:
function getConfig(request) {
var configParams = request.configParams;
var isFirstRequest = configParams === undefined;
var lst=["A","B","C"]; // your values obtained from REST
var tmp=config.newSelectSingle(); //add element to side
var element=tmp.setId("state").setName("State").setIsDynamic(true); // set name and id
for(var i in lst) // set all the values:
{
element = element.addOption(config.newOptionBuilder().setLabel(lst[i]).setValue(lst[i]))
}
if(isFirstRequest || configParams.state==undefined) // no state selected yet
{
config.setIsSteppedConfig(true); // stop here
}
else
{
// next dropdown element,
// Rest API with element set to: configParams.state
var lst2= ["x","y","z"]
var tmp2=config.newSelectSingle(); //add element to side
var element2=tmp2.setId("element2").setName("Element 2 depends on "+configParams.state).setIsDynamic(true); // set name and id
for(var i in lst2) // set all the values:
{
element2 = element2.addOption(config.newOptionBuilder().setLabel(lst2[i]).setValue(lst2[i]))
}
// code for 3rd
}
}
If the user changes the first dropdown value alle other drop downs have to be reset. This may be a bit tricky.

How can I change focus between panels in a StackPanel using GAS

I have a stackpanel containing 3 panels.
After the user clicks a button on page-1, I want page-2 to become visible.
How can I achieve this?
Edit-1
As I thought the question I asked really is a general one, I did not provide code.
But Serge insas and Zig Mandell asked for code, so here it is.
function doGet()
{
var app = UiApp.createApplication();
var stackPanel = app.createStackPanel().setSize('100%', '100%'); //Create stack panel
var onClick = app.createServerHandler('onClick');
var button = app.createButton('Button on second panel...').setId('btnPageTwo').addClickHandler(onClick);
//add widgets to each stack panel, and name the stacked panels
stackPanel.add(app.createLabel('Text on first panel...'), 'One');
stackPanel.add(button, 'Two');
stackPanel.add(app.createLabel('Text on third Panel...'), 'Three');
app.add(stackPanel); //Add the panel to the application
return app;
}
function onClick(e)
{
Logger.log('In onClick --> show stackPanel "Three" now');
}
In this example I would like to show panel Two at startup and after clicking the button I would like to show panel 3.
I tried using focusPanels, but that didn't help
function doGet()
{
var app = UiApp.createApplication();
var stackPanel = app.createStackPanel().setSize('100%', '100%'); //Create stack panel
// FocusPanels are limited to contain ONE widget
var focusOne = app.createFocusPanel().setId('focusOne');
var focusTwo = app.createFocusPanel().setId('focusTwo');
var focusThree = app.createFocusPanel().setId('focusThree');
// Create panels to overcome the one-widget-limitation of focuspanels
var ver = app.createVerticalPanel().setId('ver');
var hor = app.createHorizontalPanel().setId('hor');
var tab = app.createTabPanel().setId('tab');
var tabOne = app.createVerticalPanel().setId('tabOne');
var tabTwo = app.createHorizontalPanel().setId('tabTwo');
tab.add(tabOne, 'One').add(tabTwo, 'Two');
focusOne.add(ver);
focusTwo.add(hor);
focusThree.add(tab);
var labOne = app.createLabel('Text on first panel...');
var labThree = app.createLabel('Text on second tab of third panel...');
var onClick = app.createServerHandler('onClick');
var button = app.createButton('Button on second panel...').setId('btnPageTwo').addClickHandler(onClick);
ver.add(labOne);
hor.add(button);
tabTwo.add(labThree);
tab.selectTab(1); // Select second tab
//add widgets to each stack panel, and name the stack panel
stackPanel.add(focusOne, 'stackOne').add(focusTwo, 'stackTwo').add(focusThree, 'stackThree');
app.add(stackPanel); //Add the panel to the application
return app;
}
function onClick(e)
{
Logger.log('In onClick --> show focusPanel "Three" now');
var app = UiApp.getActiveApplication();
var focusThree = app.getElementById('focusThree');
focusThree.setFocus(true);
return app;
}
Unfortunately this has been the subject of an enhancement request for quite a while (dec 2012) but I'm afraid Google won't do anything about it since they stopped UiApp development (they recommend switching to HTMLService).
You could eventually use tabPanel instead, this one has all the necessary features.
Test here
code below :
function doGet() {
var app = UiApp.createApplication();
var tabPanel = app.createTabPanel().setSize('100%', '100%').setId('tabP'); //Create tab panel
var onClick = app.createServerHandler('onClick');
var button = app.createButton('Button on second panel...').setId('btnPageTwo').addClickHandler(onClick);
//add widgets to each tab panel, and name the tabed panels
tabPanel.add(app.createLabel('Text on first panel...'), 'One');
tabPanel.add(button, 'Two');
tabPanel.add(app.createLabel('Text on third Panel...'), 'Three');
app.add(tabPanel); //Add the panel to the application
tabPanel.selectTab(1);
return app;
}
function onClick(e){
var app = UiApp.getActiveApplication();
var tabP = app.getElementById('tabP').selectTab(2);
return 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.

showDocsPicker - Add to a popup?

I have a gadget that is very small and placed in a sidebar such that its size is about 100px wide. I have a button that when clicked opens the showDocsPicker. I am looking for a solution where I can add the UI of the showDocsPicker to a popup or something such that the full view of the dialog can be seen... Can anyone point me in the right direction? I've seen this in the documentation which is not encouraging:
"Unlike most UiApp objects, DocsListDialog should not be added to the UiInstance."
Anyone else try this?
Here is a sample code which will open docsPicker in fullView.
function doGet(){
var app = UiApp.createApplication();
var btn = app.createButton('Show Docs Picker');
app.add(btn);
var handler = app.createServerHandler('showdocsPicker_');
btn.addClickHandler(handler);
return app;
}
function showdocsPicker_(e){
var app = UiApp.getActiveApplication();
var handler = app.createServerHandler('listSelectedDocs_');
app.createDocsListDialog().showDocsPicker().addSelectionHandler(handler).setMultiSelectEnabled(true)
//for multiple selection
.setMultiSelectEnabled(true);
return app;
}
function listSelectedDocs_(e){
var app = UiApp.getActiveApplication();
for(var i in e.parameter.items){
for(var j in e.parameter.items[i]){
app.add(app.createLabel(e.parameter.items[i][j]));
}
app.add(app.createLabel('-------------'))
}
return app;
}

What is the best way to manage two UI's?

I have created two user interfaces. How can I close the first one and activate the next? Is it possible to have two UI under Google apps script?
I have try something like:
var app = UiApp.getActiveApplication();
app.add(app.loadComponent("APPGui"));
var panel1 = app.getElementById("LoginPanel1");
panel1.setVisible(false);
return app;
The easiest way is probably to design both panels in the same GUI builder, one over each other in 2 separate panels, the 'login panel' being above the other it will mask the other one when active. As you set it 'invisible', you'll see the one underneath.
Depending on your use case the login panel might hide all or only a part of your main panel.
The GUI builder has all the necessary tools to decide which is in front or backwards.
Here's and example of three dialogs shown one after the other, maintaining state/data between them via the CacheService object.
(You could use UserProperties, ScriptProperties or even a Hidden Field as an alternative, each has their own scope though...)
Hopefully this makes sense without explaining what each dialog in the UI Builder contains.
function showDialog1(){
var app = UiApp.createApplication();
app.add( app.loadComponent("Dialog1") );
SpreadsheetApp.getActiveSpreadsheet().show(app);
}
function onDialog1OKButton(e){
CacheService.getPrivateCache().put("n1", e.parameter.n1);
var app = UiApp.getActiveApplication();
var d2 = app.loadComponent("Dialog2");
app.add(d2);
SpreadsheetApp.getActiveSpreadsheet().show(app);
}
function onDialog2OKButton(e){
var c = CacheService.getPrivateCache();
c.put("n2", e.parameter.n2);
var app = UiApp.getActiveApplication();
app.add(app.loadComponent("DialogResult"));
var n1 = c.get("n1");
var n2 = c.get("n2");
var l = app.getElementById("Label2");
l.setText( "" + n1 + " + " + n2 + " = " + (parseInt(n1) + parseInt(n2)) );
SpreadsheetApp.getActiveSpreadsheet().show(app);
}
I prefer to build multiple GUI. With this code you can jump between them.
function doGet() {
var app = UiApp.createApplication();
var base0 =app.createAbsolutePanel().setId('GUI_base0').setHeight('630px').setWidth('1125px');
app.createAbsolutePanel().setId('GUI_base1'); // create all abs_panells but not use
// you need to create all abspanels if you want to jump between them
app.createAbsolutePanel().setId('GUI_base2'); // create here all the absolute panels (1 for every GUI)
// app.createAbsolutePanel() ... GUI3, GUI4 ...
var component0 = app.loadComponent("GUI_password"); // load first GUI (his name is "password"
/// this is an example of code for the 1st GUI ////////////////////
/// I can check if the user can see the second GUI
var label_ID = app.getElementById('LB_ID');
var user = Session.getActiveUser().getEmail();
if ( user == 'XXX#yyyy.com' ) {
label_ID.setText(user).setTag(user); // only show if ....
}
////////////////////////////////////////////////////////////////////
base0.add(component0); // GUI_password over absolute panel
app.add(base0);
// handler Button1 // we can show a button only if the password is correct or is a valid user or ...
app.getElementById('BT_jump').addClickHandler(app.createServerHandler('NOW_gui1'));
return app;
};
function NOW_gui1(e) {
var app = UiApp.getActiveApplication();
var base0 = app.getElementById("GUI_base0").setVisible(false); // hide 1st abs_panel created with code
var base2 = app.getElementById("GUI_base2").setVisible(false); // hide 3rd abs_panel created with code
/// hide all others abs_panel
var base1 = app.createAbsolutePanel().setId('GUI_base1').setHeight('630px').setWidth('1125px'); // maybe get by ID ??, but this work
var component1 = app.loadComponent("GUI_1"); // load the second GUI
base1.add(component1); // load GUI_1 over 2n absolute panel
app.add(base1);
// HERE THE CODE OF THE GUI_1
// handler Button2
app.getElementById('BT_jump_1_to_2').addClickHandler(app.createServerHandler('NOW_gui2'));
return app;
};