AbsolutePanel Not Displaying Content - google-apps-script

I'm trying to display a couple of buttons at the top of the window (this works fine) below which I want to create boxes of data in a ScrollPanel and an AbsolutePanel so that it can be placed anywhere and the user can scroll to it (ultimately there's going to be a lot of boxes being displayed on the screen at once).
For some reason the content in the AbsolutePanel is not displaying. I'm sure I've just missed something stupid but hopefully someone can let me know where I've gone wrong.
function doGet()
{
var app = UiApp.createApplication();
var ver = app.createVerticalPanel();
app.add(ver);
var hor = app.createHorizontalPanel();
ver.add(hor);
var add = app.createButton("Add");
hor.add(add);
var rem = app.createButton("Remove");
hor.add(rem);
var scr = app.createScrollPanel();
scr.setWidth("100%");
scr.setHeight("100%");
ver.add(scr);
var abs = app.createAbsolutePanel();
abs.setWidth("100%");
abs.setHeight("100%");
scr.add(abs);
var b1v = app.createVerticalPanel();
b1v.setBorderWidth(1);
abs.add(b1v, 50, 50);
var b1n = app.createLabel("Text 1");
b1v.add(b1n);
var b1b = app.createLabel("Text 2");
b1v.add(b1b);
var b1c = app.createLabel("Text 3");
b1v.add(b1c);
return app;
}
Alternatively, if anyone knows how to display a hierarchical chart in a GAS UI, that would be awesome, too. I tried using Google Charts and the HTML object in GAS, but it strips out any scripts.

Thanks, I also found if I set the height of the VerticalPanel to 100% and the height of the second row to 100% it works more how I was after...
function doGet()
{
var app = UiApp.createApplication();
var ver = app.createVerticalPanel();
ver.setSize("100%", "100%"); // Changed this
app.add(ver);
var hor = app.createHorizontalPanel();
ver.add(hor);
var add = app.createButton("Add");
hor.add(add);
var rem = app.createButton("Remove");
hor.add(rem);
var scr = app.createScrollPanel();
scr.setWidth("100%");
scr.setHeight("100%");
ver.add(scr);
ver.setCellHeight(scr, "100%"); // And changed this
var abs = app.createAbsolutePanel();
abs.setWidth("100%");
abs.setHeight("100%");
scr.add(abs);
var b1v = app.createVerticalPanel();
b1v.setBorderWidth(1);
abs.add(b1v, 50, 50);
var b1n = app.createLabel("Text 1");
b1v.add(b1n);
var b1b = app.createLabel("Text 2");
b1v.add(b1b);
var b1c = app.createLabel("Text 3");
b1v.add(b1c);
return app;
}

The size definition of your absolute panel is the issue, if you define it in pixels then everything works. In % is remains invisible. To debug that I assigned a color to the panel to see what happens.
try like that :
function doGet(){
var app = UiApp.createApplication();
var ver = app.createVerticalPanel();
app.add(ver);
var hor = app.createHorizontalPanel();
ver.add(hor);
var add = app.createButton("Add");
hor.add(add);
var rem = app.createButton("Remove");
hor.add(rem);
var scr = app.createScrollPanel();
ver.add(scr);
var abs = app.createAbsolutePanel().setStyleAttributes({'background-color':'#DDD'})
.setWidth("1000px")
.setHeight("2000px");
scr.add(abs);
var b1v = app.createVerticalPanel();
b1v.setBorderWidth(1);
abs.add(b1v,100,100);
var b1n = app.createLabel("Text 1");
b1v.add(b1n);
var b1b = app.createLabel("Text 2");
b1v.add(b1b);
var b1c = app.createLabel("Text 3");
b1v.add(b1c);
return app;
}

Related

Adding a ClientHandler like loading bar to a ServerClickHandler

I'm using the code below to run a a function that takes a while to load. My question is, without a lot of modification, is there an easy way of adding something like a clienthandler so that in the midst of running the function it says something along the lines of "Loading...?"
function doGet(e) {
var app = UiApp.createApplication().setTitle('New app');
var grid = app.createGrid(1, 2);
grid.setWidget(0, 0, app.createLabel('First Name + Last Name (Case Sensitive):'));
grid.setWidget(0, 1, app.createTextBox().setName('userName').setId('userName'));
var panel = app.createVerticalPanel();
panel.add(grid);
var buttonPanel = app.createHorizontalPanel();
var button = app.createButton('Submit');
var submitHandler = app.createServerClickHandler('submit')
submitHandler.addCallbackElement(grid);
button.addClickHandler(submitHandler);
buttonPanel.add(button);
var clearButton = app.createButton('Clear');
var clearHandler = app.createServerClickHandler('clear');
clearButton.addClickHandler(clearHandler);
buttonPanel.add(clearButton);
var statusLabel = app.createHTML("").setId('status').setVisible(false);
panel.add(statusLabel);
panel.add(buttonPanel);
app.add(panel);
return app;
};
function clear() {
var app = UiApp.getActiveApplication();
app.getElementById('userName').setValue('');
app.getElementById('status').setVisible(false)
return app;
};
Yes, indeed. That is what client handlers are for.
function doGet(e) {
var app = UiApp.createApplication().setTitle('New app');
var grid = app.createGrid(1, 2);
grid.setWidget(0, 0, app.createLabel('First Name + Last Name (Case Sensitive):'));
grid.setWidget(0, 1, app.createTextBox().setName('userName').setId('userName'));
/* Have the widget ready */
var statusLabel = app.createHTML("").setId('status').setVisible(false);
var panel = app.createVerticalPanel();
panel.add(grid);
var buttonPanel = app.createHorizontalPanel();
var button = app.createButton('Submit');
var submitHandler = app.createServerClickHandler('submit')
submitHandler.addCallbackElement(grid);
button.addClickHandler(submitHandler);
buttonPanel.add(button);
var clearButton = app.createButton('Clear');
var clearHandler = app.createServerClickHandler('clear');
/* Create the client handler */
var plswait = app.createClientHandler().forTargets(statusLabel).setText('Loading...');
clearButton.addClickHandler(clearHandler).addClickHandler(plswait);
buttonPanel.add(clearButton);
panel.add(statusLabel);
panel.add(buttonPanel);
app.add(panel);
return app;
};
function clear() {
var app = UiApp.getActiveApplication();
app.getElementById('userName').setValue('');
app.getElementById('status').setVisible(false).setText('');
return app;
};
It can be more pleasant if you add an image to your status label, here is an example using a transparent animated gif : (simply replace in Srik's code)
var statusLabel = ui.createHorizontalPanel().add(ui.createImage('https://dl.dropboxusercontent.com/u/211279/loading3T.gif'))
.add(ui.createHTML("Loading...")).setId('status').setVisible(false);// Label + animated gif, the text in the HTML widget can be there from the start.
Edit : just noticed something was missing in Srik's code... the clientHandler should go like this :
var plswait = app.createClientHandler().forTargets(statusLabel).setVisible(true);// and eventually setText(' blah blah...') if you didn't define/change it before/elsewhere
Note : now that you have a clientHandler you could also make use of it to setEnabled(false) the button that triggered it to avoid multiple clicks... simply add .forEventSource().setEnabled(false) to your clientHandler.

Image is loaded after the process completion and remains after that

My code is below. It will accept data from the input text; then it will fetch the recent newest feed from stackoverflow(based in the input) in google spreadsheet.
I have(wanted) set an external gif image to be shown as a progress indicator while fetching of rss feed and its processing is going on.
Problem is: When i remove the commented part; that gif image will never be visible to the user and when that is remained as a comment; that gif image is being loaded by the app after the completion of the process and remained then after.
I want it to be visible only when the process(fetching of rss and processing of it) is going on. So is there any way to make it possible?
function stackoverflow(){
var app =UiApp.createApplication().setHeight(380).setWidth(800);
app.setTitle("Enter tag name");
var mydoc=SpreadsheetApp.getActiveSpreadsheet();
var txtBox = app.createTextBox().setFocus(true).setWidth("150").setId("ticker").setName("ticker");
var mainpanel = app.createHorizontalPanel().setId('mainpanel');
mainpanel.add(txtBox);
var subbtn = app.createButton("Get posts!").setId("tick").setWidth("80");
mainpanel.add(subbtn);
var myloadingimg=app.createImage("http://schedule.msu.edu/img/InProgress.gif").setHeight("26").setWidth("26").setId("loadingimg");
mainpanel.add(myloadingimg.setVisible(false));
app.add(mainpanel);
var panel = app.createVerticalPanel().setId('panel');
var submitHandler = app.createServerHandler("clicker").addCallbackElement(mainpanel);
subbtn.addClickHandler(submitHandler);
app.add(panel);
mydoc.show(app);
}
function clicker(e){
var app = UiApp.getActiveApplication();
var txtBox = app.getElementById("ticker");
app.getElementById("loadingimg").setVisible(true);
var panel=app.getElementById("panel");
app.remove(1);
var panel = app.createVerticalPanel().setId('panel');
var stackurl = "http://stackoverflow.com/feeds/tag?tagnames="+e.parameter.ticker+"&sort=newest";
var stackXML = UrlFetchApp.fetch(stackurl).getContentText();
var stackDOC = Xml.parse(stackXML, false);
var stackentry = stackDOC.getElement().getElements('entry');
for (var i = 0; i < stackentry.length; i++) {
var result = stackentry[i];
panel.add(app.createHTML("<br><b>Post Title: </b>"+ result.getElement('title').getText()+"<br>"));
panel.add(app.createAnchor('', '') .setText("Post URL").setHref(result.getElement('link').getAttribute('href').getValue()));
panel.add(app.createHTML("<br>"));
}
var scroll = app.createScrollPanel().setPixelSize(760, 280);
scroll.add(panel);
app.add(scroll);
//app.getElementById("loadingimg").setVisible(false);
return app;
}
function onOpen()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
menuEntries.push({name:'stackoverflow',functionName:'stackoverflow'});
ss.addMenu("f2", menuEntries);
}
You can make use of clientHandlers which are meant for precisely such cases.
function stackoverflow(){
...
var clientHandler = app.createClientHandler().forTargets(myloadingimg).setVisible(true);
var submitHandler = app.createServerHandler("clicker").addCallbackElement(mainpanel);
subbtn.addClickHandler(submitHandler).addClickHandler(clientHandler);
...
}
function clicker(e){
var app = UiApp.getActiveApplication();
....
app.getElementById("loadingimg").setVisible(false);
return app;
}

Cannot dynamically update UI Grid Class Google Apps Script

I've been trying to get my UIAPP grid to dynamically add objects based on a button insert button but cannot seem to do so. I don't know why this isn't working. Any help would be greatly appreciated.
function trackColumns()
{
var app = UiApp.createApplication().setWidth(500).setHeight(360).setTitle('Step 1: Select Information to Track');
var panel = app.createVerticalPanel().setId("settingsPanel");
var headerpanel = app.createVerticalPanel().setId("headerPanel").setStyleAttribute("background", "silver").setWidth(500);
var columnPanel = app.createVerticalPanel();
var mainGrid = app.createGrid(5, 1).setId("mainGrid");
var columnGrid =app.createGrid(1,1).setId("columnGrid");
var columnspanel = app.createHorizontalPanel().setId("columnspanel");
var columnname = app.createTextBox().setText("Name");
columnspanel.add(columnname);
var addcolumnspanel = app.createHorizontalPanel().setId("addcolumnspanel");
var addbuttonhandler = app.createServerHandler("addcolumn");
addbuttonhandler.addCallbackElement(columnGrid);
var addbutton = app.createButton().setId("btnaddcolumn").setText("Add another column").addClickHandler(addbuttonhandler);
addcolumnspanel.add(addbutton);
columnGrid.setWidget(0, 0, columnspanel);
mainGrid.setWidget(1, 0, columnGrid);
mainGrid.setWidget(2, 0, addcolumnspanel);
panel.add(mainGrid);
app.add(panel);
ss.show(app);
return app;
}
function trackster_addcolumn(e) {
var app = UiApp.getActiveApplication();
var columnspanel = app.createHorizontalPanel().setId("columnspanel");
var columnname = app.createTextBox().setText("Name");
var columntype = app.createListBox();
columntype.addItem("Text");
columntype.addItem("DropDown");
columntype.addItem("Date");
columntype.addItem("Number");
columnspanel.add(columnname);
columnspanel.add(columntype);
var columngrid = e;
columngrid.setWidget(3,0,columnspanel);
return app;
}
From what I can tell...
Would need to initialize this grid for 4 rows if you're wanting to set some thing in (3,0) later in the server function.
var columnGrid =app.createGrid(1,1).setId("columnGrid"); >> var columnGrid =app.createGrid(4,1).setId("columnGrid");
Server function name just needs to match what's in the createServerHandler()...
function trackster_addcolumn(e) >> function addcolumn(e)
e has the values of all the widgets passed through to the server function, not the actual widgets themselves. To get grid...
var columngrid = e; >> var columngrid = app.getElementById('columngrid');

Not replacing e.parameter

I created this script to be able to send an email after a grid has been filled with information. Before the email is sent, another display comes in an warns the user to continue only if the information is correct. At the end the script sends an email to me, with the info entered by the user. The problem is here, when I received the email, the fields that the script is suppose to replace are shown as undefined and no info is there. Any ideas on what is wrong here??
Thank you!
function runmyapp() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle('Title 1');
var grid = app.createGrid(4, 5);
grid.setWidget(0, 0, app.createLabel('Time '));
grid.setWidget(0, 1, app.createTextBox().setName('Time'));
grid.setWidget(1, 0, app.createLabel('Minutes'));
grid.setWidget(1, 1, app.createTextBox().setName('Minutes'));
grid.setWidget(2, 0, app.createLabel('Enter Name'));
grid.setWidget(2, 1, app.createTextBox().setName('Name'));
grid.setWidget(3, 0, app.createLabel('Email'));
grid.setWidget(3, 1, app.createTextBox().setName('email'));
var panel = app.createVerticalPanel();
panel.add(grid);
var button = app.createButton('Submit').setId("button");
var handler2 = app.createServerHandler('dis');
handler2.addCallbackElement(grid);
button.addClickHandler(handler2);
var handler = app.createServerHandler('disc');
handler.addCallbackElement(grid);
button.addClickHandler(handler);
// Add the button to the panel and the panel to the application, then display the application app
panel.add(button);
app.add(panel);
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
function dis(e){
var app = UiApp.getActiveApplication();
app.getElementById("button").setText("Request is in process, please wait!").setEnabled(false);
return app;
};
function disc(e){
var app = UiApp.getActiveApplication();
var html1 = app.add(app.createHTML("<p><p>Hello Expert,</p>"+
"<p>By clicking OK you agree that your information is correct</p>");
var button = app.createButton('Ok').setId("button");
app.add(button);
var handler2 = app.createServerHandler('gsnot');
button.addClickHandler(handler2);
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
return app;}
function gsnot(e) {
var advancedArgs = {bcc:e.parameter.email};
var emailSubject = "Subject";
var address ="albdominguez25#gmail.com";
var emailTemplate =SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Templates").getRange("A1").getValue( ) ;
emailTemplate = emailTemplate.replace("TIME", e.parameter.Times).replace("MIN", e.parameter.Minutes).replace("EXP", e.parameter.Name);
MailApp.sendEmail(address, emailSubject, emailTemplate, advancedArgs);
Browser.msgBox("Your Email has been sent!");
var app = UiApp.getActiveApplication();
app.close();
// The following line is REQUIRED for the widget to actually close.
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
To make a widget value show on your e.parameter you need to add it (or a parent panel) as a callback element on the handler. Like this:
function runmyapp() {
//...
var grid = app.createGrid(4, 5).setId('grid');
//...
}
function disc(e){
//...
var grid = app.getElementById('grid');
var handler2 = app.createServerHandler('gsnot').addCallbackElement(grid);
//...
}
Keep Henrique's answer as best one please.
You can try to change your disc(e) function like this :
function disc(e){
var app = UiApp.getActiveApplication();
var html1 = app.add(app.createHTML("<p><p>Hello Expert,</p>"+
"<p>By clicking OK you agree that your information is correct</p>"));
var grid = app.getElementById('grid')
var button = app.createButton('Ok').setId("button");
app.add(button);
var handler3 = app.createServerHandler('gsnot');// use a different name to avoid confusion
handler3.addCallbackElement(grid);
button.addClickHandler(handler3);
return app;}
And, also, there is a typo in your code in this line :
emailTemplate = emailTemplate.replace("TIME", e.parameter.Times).replace("MIN", e.parameter.Minutes).replace("EXP", e.parameter.Name);
Time has no 's' at the end in the original name ! ;)
and, last point, if I where you I wouldn't call show(app) in disc so the UI would keep the data validation while confirming... (but that's a matter of choice ;-)

Google apps script : drop a document in My drive from a form in google site

I use the following code to create a kind of dropbox for my students. The form is embedded on a google site page . When the file is sent in the "dropbox" folder, it is automatically converted in a text file. I did try with a .doc, .xls and .pdf...
Should it be possible to avoid this problem ?
Thanks a lot
Jean-Paul
var folderName = "Assignments-Spring-2011";
function doGet() {
var app = UiApp.createApplication().setTitle("Upload Assignment");
app.setHeight(180);
var form = app.createFormPanel().setId('frm').setEncoding('multipart/form-data');
var formContent = app.createGrid().resize(6,2);
form.add(formContent);
formContent.setWidget(1, 0, app.createLabel('Assignment Number:'));
var assignmentNumberList = app.createListBox();
assignmentNumberList.addItem("Assignment 1");
assignmentNumberList.addItem("Assignment 2");
assignmentNumberList.addItem("Assignment 3");
assignmentNumberList.addItem("Assignment 4");
assignmentNumberList.addItem("Assignment 5");
assignmentNumberList.addItem("Assignment 6");
assignmentNumberList.addItem("Assignment 7");
assignmentNumberList.addItem("Assignment 8");
formContent.setWidget(1, 1, assignmentNumberList.setName('assignmentNumber'));
formContent.setWidget(3, 0, app.createLabel('Assignment File:'));
formContent.setWidget(3, 1, app.createFileUpload().setName('thefile'));
formContent.setWidget(5, 0, app.createSubmitButton('Submit Assignment!'));
// thank you panel
var panel = app.createSimplePanel().setVisible(false).setId("thankyouPanel");
var label = app.createLabel("Thank you for submitting the Assignment").setStyleAttribute("fontSize", "16px");
panel.add(label);
app.add(panel);
app.add(form);
return app;
}
function doPost(e) {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var name = Session.getActiveUser().getUserLoginId();
var assignmentFile = e.parameter.file;
var uploadBlob = Utilities.newBlob (assignmentFile, "text/plain",e.parameter.assignmentNumber+"-"+name+"-"+e.parameter.thefile.name );
var doc = DocsList.createFile(uploadBlob);
// get assignment folder
var folder = DocsList.getFolder(folderName);
doc.addToFolder(folder);
var app = UiApp.getActiveApplication();
var form = app.getElementById("frm").setVisible(false);
var panel = app.getElementById("thankyouPanel").setVisible(true);
app.close();
return app;
}
It looks as thought he code you've used is intentionally restricting it to text:
var uploadBlob = Utilities.newBlob (assignmentFile, "text/plain",e.parameter.assignmentNumber+"-"+name+"-"+e.parameter.thefile.name );
Simply eliminate that line and redirect your variables like so
var uploadBlob = e.parameter.file;
Should set you straight.