Preventing double click on google app script - google-apps-script

When I make double click the form submitted twice. It creates duplicated rows. How can I prevent double click ?
Thank you!
function doGet(e) {
//Logger.log( Utilities.jsonStringify(e) );
if (!e.parameter.page) {
// When no specific page requested, return "home page"
return HtmlService.createTemplateFromFile('employee').evaluate()
.setTitle('care backup').setSandboxMode(HtmlService.SandboxMode.NATIVE);
}
// else, use page parameter to pick an html file from the script
return HtmlService.createTemplateFromFile(e.parameter['page']).evaluate()
.setTitle('care').setSandboxMode(HtmlService.SandboxMode.NATIVE);
}

I have not tested this, but just an option- also Set a time based trigger to run function reset every so often?
var recentSubmit = 0;
function doGet(e) {
//Logger.log( Utilities.jsonStringify(e) );
if (recentSubmit = 0){
if (!e.parameter.page) {
var recentSubmit = 1;
// When no specific page requested, return "home page"
return HtmlService.createTemplateFromFile('employee').evaluate()
.setTitle('care backup').setSandboxMode(HtmlService.SandboxMode.NATIVE);
}
// else, use page parameter to pick an html file from the script
return HtmlService.createTemplateFromFile(e.parameter['page']).evaluate()
.setTitle('care').setSandboxMode(HtmlService.SandboxMode.NATIVE);
}
Logger.log("Submitted a form to recently, try again later...");
}
function reset() {
var recentSubmit = 0;
}

You can try using the createClientHandler.forEventSource().setEnabled(false). It can disable the submit button. It's deprecated but it still works for now.
Full code implementation sample is found in this SO post:
function onOpen() {
var app = UiApp.createApplication();
app.setTitle('My Title');
app.setHeight(150);
app.setWidth(300);
var form = app.createFormPanel();
var flow = app.createFlowPanel();
flow.add(app.createHidden("action", 'action'));
flow.add(app.createLabel('My Label'));
//Submit
var submit = app.createButton('Run', app.createServerHandler('notif').addCallbackElement(form)).setId('run');
var cliHandler = app.createClientHandler().setEnabled().setEnabled(false);
submit.addClickHandler(cliHandler);
flow.add(submit);
form.add(flow);
app.add(form);
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
};
function notif(){
//DO NOTHING. JUST SHOW THE button is DISABLED.
}
button is greyed-out after clicking..

Related

Google app script return undefined before user gives answer yes/no on dialog

The method return is undefined before user clicks yes/no. According to Google app script, server process should be frozen when dialog shows up. But in my test, the value is returned before users clicks yes/no.
function getValues() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var okToInsert = true;
if (sheet.getName() !== "xxx") {
var ui = SpreadsheetApp.getUi();
var alert = ui.alert('Confirm',
'Your active sheet is not "xxx". Continue to insert?',
ui.ButtonSet.YES_NO);
if(alert == ui.Button.NO){
okToInsert = false;
}
}
return {
"okToInsert": okToInsert
};
}
This is my frontend js:
google.script.run
.withSuccessHandler(
function(selectedRange, scope) {
console.log(">>> selectedRange: " + selectedRange);
})
.withFailureHandler(
function(msg, scope) {
})
.withUserObject($scope)
.getValues();
This is how I enable the sidebar:
var ui = HtmlService.createTemplateFromFile('sidebar').evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('this is title');
SpreadsheetApp.getUi().showSidebar(ui);
I have a sample sidebar add-on called "Dialog return test" created here.
https://docs.google.com/spreadsheets/d/1eHwjHKuBIDw2WOTRU5CZAu9m9V-9mXimFyMlGXbPl-U/edit?usp=sharing
Your code runs perfectly for me:
I get the dialogue prompt and return is defined with no errors. It's likely the issue is with another part of your code, or possibly the script file itself. I would recommend trying it on a new script in a new sheets file and try and narrow the issue down from there.

Changing a Textbox to a Button in Google Script

I'm working on a todo list program in google script. I have it so that people can type in their task in a textbox, but I want it so that once they hit the enter key, the textbox turns into a button that, that says what the task is, and they will later press when they finished that task and it will return to a textbox. I can't figure out how to make any changes to the app from inside another function.
What I have so far is:
function doGet(e) {
var app = UiApp.createApplication();
var panel = app.createAbsolutePanel().setHeight("750px").setWidth("1600px");
var button = app.createButton("swag");
var enterHandler = app.createServerKeyHandler('enterPress');
enterHandler.addCallbackElement(panel);
var box = app.createTextBox().addKeyUpHandler(enterHandler);
panel.add(box,0,0);
app.add(panel);
return app;
}
function enterPress(e){
var app = UiApp.getActiveApplication();
if (e.parameter.keyCode==13){
var button2 =app.createButton('swag');
var panel = app.createAbsolutePanel().setHeight('750px').setWidth('1600px');
panel.add(button2,0,0);
app.add(panel);
}
return app;
}
It recognizes the enter press, but the changes won't return to the main app.
You can do it like this :
note : I didn't "place" the button, I guess you have an idea on how you want them to show up...
You could also use a grid to place them... as you want.
function doGet(e) {
var app = UiApp.createApplication();
var panel = app.createAbsolutePanel().setHeight("750px").setWidth("1600px");
var enterHandler = app.createServerKeyHandler('enterPress').addCallbackElement(panel);
var button = app.createButton("confirm",enterHandler).setId('swag');
var tBox = app.createTextBox().setName('tBox').setId('tBox').setWidth(300).setStyleAttributes({'textAlign':'center'});
var bBox = app.createButton("no Text",enterHandler).setVisible(false).setId('bBox').setWidth(300);
panel.add(tBox,20,20).add(bBox,20,20).add(button,140,50);
app.add(panel);
return app;
}
function enterPress(e){
var app = UiApp.getActiveApplication();
if (e.parameter.source=='bBox'){
app.getElementById('bBox').setVisible(false);
app.getElementById('tBox').setVisible(true);
}
if (e.parameter.source=='swag'){
app.getElementById('bBox').setVisible(true).setHTML(e.parameter.tBox);
app.getElementById('tBox').setVisible(false);
}
return app;
}
Test here
Edit: code modified with placement .
EDIT2 : You could also hide the enter button, I find it nicer.
function enterPress(e){
var app = UiApp.getActiveApplication();
if (e.parameter.source=='bBox'){
app.getElementById('bBox').setVisible(false);
app.getElementById('tBox').setVisible(true);
app.getElementById('swag').setVisible(true);
}
if (e.parameter.source=='swag'){
app.getElementById('bBox').setVisible(true).setHTML(e.parameter.tBox);
app.getElementById('tBox').setVisible(false);
app.getElementById('swag').setVisible(false);
}
return app;
}

Convert ModalDialog to DialogBox

In my apps script for Google Docs I'm trying to convert a ModalDialog to a DialogBox so that I can take advantage of the addCloseHandler() on DialogBoxes.
My showModalDialog works with the following GS code:
function showSheetPicker() {
var html = HtmlService.createTemplateFromFile('sheetPicker').evaluate().
setHeight(400).setWidth(600);
DocumentApp.getUi().showModalDialog(html, "Select a Sheet");
}
However, when I tried converting that to use createDialogBox(), I came up with the following:
function showSheetPicker() {
var app = UiApp.createApplication();
var autoHide = false;
var modal = true;
var dialog = app.createDialogBox(autoHide, modal);
dialog.setPopupPosition(100, 100).setSize(650, 450).setHTML(html)
.setTitle("Select a Sheet").createCloseHandler(handlingTheClose).show();
return app;
}
This is producing an error that tells me: The script completed but the returned value is not a supported return type..
What would I need to do to convert my ModalDialog to a DialogBox so that I can take advantage of the addCloseHandler()?
This is an example of a doc showing a dialogBox but the result is quite disappointing...
function myFunction() {
var app = UiApp.createApplication();
var autoHide = false;
var modal = true;
var dialog = app.createDialogBox(autoHide, modal);
dialog.setPopupPosition(100, 100).setSize(650, 450)
.setTitle('hover me').setHTML('this is a test dialog');
app.add(dialog).setHeight(450).setWidth(650);
DocumentApp.getUi().showModelessDialog(app, "Select a Sheet")
}
I've never succeeded in using this widget... good luck.
As for the closeHandler, I doubt you can use it since you won't be able to close the inner dialogBox, you will actually close the ModelessDialog in this example... (good luck again... I give up ;-)

Automatically close a Google Apps Script UiApp after five seconds

I want to automatically close this UiApp after a certain number of seconds:
function showConfirmationDialogue() {
var app = UiApp.createApplication().setHeight('80').setWidth('400');
app.setTitle('test');
var panel = app.createVerticalPanel();
app.add(panel);
var doc = SpreadsheetApp.getActive();
doc.show(app);
// this part doesn't seem to work
Utilities.sleep(5000);
app.close();
return app;
}
Thanks!
The Ui you create is shown when you call doc.show(app) and the only way you can update it or close it is to use a handler function that ends with a return app.
So it is not possible to do what you want from the same function that creates the UI since it is "returned" only one time.
I know only one trick that can achieve what you want that is using a handler trigger source that will call a closing handler function automatically using a "special" property of the checkBox widget. Here is the code, it uses a checkBox that you can of course make invisible in your final code.
function showConfirmationDialogue() {
var app = UiApp.createApplication().setHeight('80').setWidth('400');
app.setTitle('test');
var panel = app.createVerticalPanel();
app.add(panel);
var handler = app.createServerHandler('closeWindow');
var chk = app.createCheckBox('checkBox to set invisible in real function').setValue(false,true).addValueChangeHandler(handler);
app.add(chk);
chk.setValue(true,true)//.setVisible(false);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
function closeWindow(){
Utilities.sleep(5000);
var app = UiApp.getActiveApplication().close();
return app;
}
You can use the same procedure to modify the UiApp instance in any way, change a Label text, add a widget... anything you want.

doPost Twice in Google Apps Script?

I have a web-deployed form written in Google Apps Script with doGet and doPost. In the doPost, the code checks if the user has filled in the form correctly (e.g. not leaving certain things blank). If not, it highlights the things that need to be fixed and adds a warning label. If everything is all right, it writes the form data to a spreadsheet.
The problem is that it doesn't seem like doPost can be called again if the user fixes the problems.
Any thoughts? Thanks!
EDIT: I am using UiService
EDIT: Here is a very simplified version of the app:
function doGet(e) {
var app = UiApp.createApplication();
var mainForm = app.createFormPanel().setId('mainForm');
var formContent = app.createVerticalPanel().setId('formContent');
var userName = app.createTextBox().setId('userName').setName('userName');
var passport = app.createFileUpload().setName('passport');
var submitButton = app.createSubmitButton('submit here');
var submitButtonWarning = app.createLabel('Something is wrong.').setId('submitButtonWarning')
.setVisible(false);
formContent
.add(userName)
.add(passport)
.add(submitButton)
.add(submitButtonWarning);
mainForm.add(formContent);
app.add(mainForm);
return app;
}
function doPost(e) {
var app = UiApp.getActiveApplication();
var userName = e.parameter.userName;
var passport = e.parameter.passport;
if (userName == 'no') {
app.getElementById('submitButtonWarning').setVisible(true);
app.add(app.getElementById('formContent'));
return app;
} else {
app.getElementById('submitButtonWarning').setVisible(false);
app.add(app.getElementById('formContent'));
return app;
}
return app;
}
I think you are just adding the wrong UI element to the app in your doPost.
Instead of
app.add(app.getElementById('formContent'));
use
app.add(app.getElementById('mainForm'));