How can I change focus between panels in a StackPanel using GAS - google-apps-script

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;
}

Related

Embedding a button in a grid causes the grid to behave as the button?

Using Google Apps Script to build a web app, when I put a button widget in a grid widget, it seems the entire grid turns into the "button".
i.e. if I put:
var myGrid = app.createGrid(4,4);
var addButton = myGrid.setWidget(3,3,app.createButton("Add"));
var handler = app.createServerClickHandler('add');
addButton.addClickHandler(handler);
app.add(myGrid);
In the resulting web app if I click anywhere on the grid the clickhandler for the button fires. Even worse, if I embed multiple buttons in the grid, clicking anywhere on the grid fires all button clickhandlers.
Are buttons in grids not supported? Or am I doing something wrong?
Thanks.
Edit: If you want to see the behaviour for yourself, I've replicated the issue by modifying one of Google's examples. The second example for "Validators" here: https://developers.google.com/apps-script/uiapp#Validators I modified and put the textboxes and the button in a Grid Widget. After entering numbers in the text boxes, every time you click anywhere on the grid the "add" clickhandler will fire and add the numbers again:
function doGet() {
var app = UiApp.createApplication();
var rgx = "^\\$?[0-9]+$";
// Create input boxes and button.
//var textBoxA = app.createTextBox().setId('textBoxA').setName('textBoxA');
//var textBoxB = app.createTextBox().setId('textBoxB').setName('textBoxB');
var myGrid = app.createGrid(4,4);
myGrid.setWidget(0,0,app.createTextBox().setId('textBoxA').setName('textBoxA'));
myGrid.setWidget(0,1,app.createTextBox().setId('textBoxB').setName('textBoxB'));
var textBoxA = app.getElementById('textBoxA');
var textBoxB = app.getElementById('textBoxB');
var addButton = myGrid.setWidget(3,3,app.createButton("Add").setEnabled(false));
var label = app.createLabel("Please input two numbers");
// Create a handler to call the adding function.
// Two validations are added to this handler so that it will
// only invoke 'add' if both textBoxA and textBoxB contain
// numbers.
var handler = app.createServerClickHandler('add').validateMatches(textBoxA,rgx).validateMatches(textBoxBrgx).addCallbackElement(textBoxA).addCallbackElement(textBoxB);
// Create a handler to enable the button if all input is legal
var onValidInput = app.createClientHandler().validateMatches(textBoxA,rgx).validateMatches(textBoxB,rgx).forTargets(addButton).setEnabled(true).forTargets(label).setVisible(false);
// Create a handler to mark invalid input in textBoxA and disable the button
var onInvalidInput1 = app.createClientHandler().validateNotMatches(textBoxA,rgx).forTargets(addButton).setEnabled (false).forTargets(textBoxA).setStyleAttribute("color", "red").forTargets(label).setVisible(true);
// Create a handler to mark the input in textBoxA as valid
var onValidInput1 = app.createClientHandler().validateMatches(textBoxA,rgx).forTargets(textBoxA).setStyleAttribute("color", "black");
// Create a handler to mark invalid input in textBoxB and disable the button
var onInvalidInput2 = app.createClientHandler().validateNotMatches(textBoxB,rgx).forTargets(addButton).setEnabled(false).forTargets(textBoxB).setStyleAttribute("color", "red").forTargets(label).setVisible(true);
// Create a handler to mark the input in textBoxB as valid
var onValidInput2 = app.createClientHandler().validateMatches(textBoxB,rgx).forTargets(textBoxB).setStyleAttribute("color","black");
// Add all the handlers to be called when the user types in the text boxes
textBoxA.addKeyUpHandler(onInvalidInput1);
textBoxB.addKeyUpHandler(onInvalidInput2);
textBoxA.addKeyUpHandler(onValidInput1);
textBoxB.addKeyUpHandler(onValidInput2);
textBoxA.addKeyUpHandler(onValidInput);
textBoxB.addKeyUpHandler(onValidInput);
addButton.addClickHandler(handler);
app.add(myGrid);
//app.add(textBoxB);
//app.add(addButton);
app.add(label);
return app;
}
function add(e) {
var app = UiApp.getActiveApplication();
var result = parseFloat(e.parameter.textBoxA) + parseFloat(e.parameter.textBoxB);
var newResultLabel = app.createLabel("Result is: " + result);
app.add(newResultLabel);
return app;
}
When you write
var addButton = myGrid.setWidget(3,3,app.createButton("Add"));
and then you add a handler to the variable addButton you are in fact adding the handler to the grid, not to the button.
I would suggest to rewrite it like this (I commented the code) and it will work normally
var myGrid = app.createGrid(4,4);
var addButton = app.createButton("Add");
myGrid.setWidget(3,3,addButton);// here you add the button to the grid
var handler = app.createServerClickHandler('add');
addButton.addClickHandler(handler);
app.add(myGrid);// only the grid must be added, the button is already in it
or, if you want to make it more compact :
var handler = app.createServerClickHandler('add');
var myGrid = app.createGrid(4,4).setWidget(3,3,createButton("Add",handler));// here you add the button to the grid
app.add(myGrid);// only the grid must be added, the button is already in it

google script unable to update web page

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;
}

Display SplitLayoutPanel and it's children elements

I can't seem to make a SplitLayoutPanel display it's children elements. GAS seems to support this class as it's noted in the documentation.
https://developers.google.com/apps-script/class_splitlayoutpanel
Here's my attempt at the code. Any suggestions would be greatly appreciated. My assumption is this gives the user a splitter that they can drag to resize the panels (which is ideal for what I'm going for. A left side panel with a right side panel with more details.
function doGet(e) {
var app = UiApp.createApplication();
//code goes here   
var mainPanel = app.createSplitLayoutPanel().setId('mainPanel')
.setVisible(true);
app.add(mainPanel);
var eastPanel = app.createVerticalPanel().setId('eastPanel');
eastPanel.add(app.createLabel('eastPanel loaded'));
mainPanel.addEast(eastPanel, 500);
var westPanel = app.createVerticalPanel().setId('westPanel');
westPanel.add(app.createLabel('westPanel loaded'));
mainPanel.addWest(westPanel, 500);
return app;
}
What did I miss?
A single line mainPanel.setSize('100%', '100%'); is missed. The following code works.
function doGet(e) {
var app = UiApp.createApplication();
//code goes here
var mainPanel = app.createSplitLayoutPanel().setId('mainPanel')
.setVisible(true);
mainPanel.setSize('100%', '100%');
app.add(mainPanel);
var eastPanel = app.createVerticalPanel().setId('eastPanel');
eastPanel.add(app.createLabel('eastPanel loaded'));
mainPanel.addEast(eastPanel, 500);
var westPanel = app.createVerticalPanel().setId('westPanel');
westPanel.add(app.createLabel('westPanel loaded'));
mainPanel.addWest(westPanel, 500);
return app;
}

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;
};