Single Google Form for multiple Sheets [duplicate] - google-apps-script

This question already has answers here:
Google Forms embedded in Google Sheets Unclickable - CORS conflict
(2 answers)
Closed 2 years ago.
Due to ongoing development versioning, plus seemingly insurmountable problems implementing user permissions workarounds, I need to capture form data linked to a sheet which is not exposd to the users. Instead I want to launch the form from a separate spreadsheet app using a custom menu. Yet despite thorough Google searches, and the tantalizingly named 'FormApp.openById' method, I can't find a way to accomplish this.
I know I'm off track here; could anyone please point me to the way back?

Step 1: Create Form
Normal operating procedure - create your form either through a script or using the Forms UI. Capture the ID of the form. For instance, from the URL when in the editor:
https://docs.google.com/forms/d/1-AWccGNgdJ7_5Isjer5K816UKNSaUPSlvlkY3dGJ1UQ/edit
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Attach a spreadsheet to capture responses. (We're not going to do anything more with that here.)
Step 2: Client Script
In the user-accessible spreadsheet, create a container-bound script (so it has access to the Spreadsheet UI). The following script produces a custom menu with a selection that launches a form in a Ui popup.
/**
* Uses the Forms service to get a handle on an existing form, then retrieve its published URL.
* Uses the UrlFetch Service to get a copy of the HTML for the form.
* Uses the HtmlService to embed the form's HTML in a Spreadsheet UI.
* ... which is finally shown using Spreadsheet.show().
*/
function launchForm() {
var formID = '1-AWccGNgdJ7_5Isjer5K816UKNSaUPSlvlkY3dGJ1UQ';
var form = FormApp.openById(formID);
var formUrl = form.getPublishedUrl();
var response = UrlFetchApp.fetch(formUrl);
var formHtml = response.getContentText();
var htmlApp = HtmlService
.createHtmlOutput(formHtml)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('Ta Daaa!')
.setWidth(500)
.setHeight(450);
SpreadsheetApp.getActiveSpreadsheet().show(htmlApp);
}
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Launch Form",
functionName : "launchForm"
}];
sheet.addMenu("Custom Menu", entries);
};
Demo
Here's what you see when you select "Launch Form" from the "Custom Menu". One little annoyance, though - when the form is submitted, the user is taken to another browser window or tab. In the spreadsheet, the UI remains open, and needs to be manually closed. That problem is gone with IFRAME sandboxing!
EDIT: Changes in the ECMA sandbox defaults were introduced recently, which require that the sandbox mode be explicitly set to NATIVE for this technique to work. Code has been updated.
EDIT Again: The newer IFRAME sandbox mode keeps the whole form experience inside the dialog.

Mogsdad got me on the right track, but in order for the submit button to work, I had to embed it directly in the code.
1) Create a form and in the forms menu, select "Embed form in a webpage"
2) Copy the entire block of code that appears. It should look similar to this:
<iframe src="https://docs.google.com/forms/d/e/<YOUR_ID_NUMBER_HERE/viewform?embedded=true" width="500" height="450" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe>
3) Add this function to your script page
function launchForm() {
var embeddedHtml = '<iframe src="https://docs.google.com/forms/d/e/<YOUR_ID_NUMBER_HERE/viewform?embedded=true" width="500" height="450" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe>'
var htmlApp = HtmlService.createHtmlOutput(embeddedHtml)
SpreadsheetApp.getUi().showModalDialog(htmlApp, 'Title');
}
If you'd like the formatting and banner of your form to stay, remove the ?embedded=true off of the embedded link https://docs.google.com/forms/d/e/<YOUR_ID_NUMBER_HERE/viewform?embedded=true

Related

Google script - link to download /export file from google sites

on google sites i have a search page and i need to insert a button to export to a spreadsheet the search. The script creates a spreadsheet with the information and provides a download link.
How can I do this without reloading the search page?
is it possible to open a modal or a window over the page to display the link?
how can I fill in the doGet() event argument from the search page?
In another implementation, I had a problem with the sandbox, saying that downloading was disabled in chrome since update 83. is there any way to solve this?
Or if anyone has another solution for all of that, it would be most welcome. I appreciate the collaboration.
my code.gs:
function doGet(e)
{
var report = e.parameter.report; //// how to fill a 'parameter' in search.html ?
if(report)
{
var planilha = SpreadsheetApp.create('asd');
// fill the Spreadsheet
var ssID = planilha.getId();
var URL = 'https://docs.google.com/spreadsheets/d/'+ssID+'/export?format=xlsx';
return ?? /// returns what exactly?
}
return HtmlService.createTemplateFromFile('search').evaluate();
}
There is already a reported issue on Public Issue Tracker to to add "allow-downloads" in HtmlService.XFrameOptionsMode.ALLOWALL
You can go there and click on the star besides the issue title so it gets more visibility.

Can I use Slides API to add an "Agree to Terms" dialogue before allowing viewer access to a Slides presentation?

I have a Google Slides presentation that I'd like to gate with a request to agree to "Terms & Conditions" before viewing. (The dialogue box would include an external link to the legal fine print.)
I see that with Google App Script adding a dialogue box is possible, but if one can be customized in this manner is unclear to me.
Thanks in advance for any help on this.
You want to open a dialog, when users open the Google Slides.
In this case, users are logged in to each Google account.
You want to make users show "Terms & Conditions" by the external link.
When users click "ok" button, when users reopen the Google Slides, you don't want to open the dialog.
When users click "cancel" button, when users reopen the Google Slides, you want to open the dialog.
You want to use a custom dialog for this.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Issue and workarounds:
In order to open the custom dialog when users open the Google Slides, it is required to use the installable trigger. But at Google Slides, unfortunately, in the current stage, the OnOpen event trigger cannot be used as the installable trigger. By this, when users open the Google Slides, the custom dialog cannot be opened. It seems that this is the current specification. So in order to achieve abour your goal, it is required to think of the workaround. In this answer, I would like to propose the following 2 workarounds.
Workaround 1:
Fortunately, at Google Slides, the simple trigger can be used instead of the installable trigger which cannot be used. In this case, the OnOpen event trigger can be used as the simple trigger. So in this workaround, the built-in dialog is used with the simple trigger.
Sample script:
Please copy and paste the following script to the container-bound script of the Google Slides and save it. When you open the Google Slides, a dialog is opened. When "ok" is clicked, keyObject is set to the PropertiesService. By this, when you open the Google Slides again, the dialog is not opened. In this case, getUserProperties() is used. So keyObject can be used for each users.
function onOpen() {
var keyObject = {key1: "value1"}; // Here, key and value for checking whether user had clicked "ok" button.
var prop = PropertiesService.getUserProperties();
var value = prop.getProperty(Object.keys(keyObject)[0]);
if (value != keyObject.key1) {
var ui = SlidesApp.getUi();
var result = ui.alert('sample title', 'Please check this link.\nhttps://###/', ui.ButtonSet.YES_NO);
if (result == ui.Button.YES) {
ui.alert('"ok" was clicked.');
prop.setProperties(keyObject);
} else {
ui.alert('"cancel" was clicked.');
}
}
}
In this case, the URL cannot be clicked. So user is required to access to the URL. I think that this is the limitation when this workaround is used.
If you want to delete keyObject. Please use the following script.
function deleteProperty() {
var keyObject = {key1: "value1"};
var prop = PropertiesService.getUserProperties();
prop.deleteProperty(Object.keys(keyObject)[0]);
}
Workaround 2:
In this workaround, the built-in dialog and the custom menu are used with the simple trigger. In this case, the custom dialog is used.
Sample script:
Please copy and paste the following script to the container-bound script of the Google Slides and save it. When you open the Google Slides, a dialog is opened. The dialog shows "Please open dialog from the menu.". Users click "ok" button and open the custom dialog from the custom menu. When "ok" is clicked at the custom dialog, keyObject is set to the PropertiesService. By this, when you open the Google Slides again, the dialog is not opened. In this case, getUserProperties() is used. So keyObject can be used for each users.
function onOpen() {
var keyObject = {key1: "value1"};
var prop = PropertiesService.getUserProperties();
var value = prop.getProperty(Object.keys(keyObject)[0]);
if (value != keyObject.key1) {
var ui = SlidesApp.getUi();
ui.createMenu('Open dialog').addItem('Open dialog', 'openDialog').addToUi();
var result = ui.alert('sample title', 'Please open dialog from the menu.', ui.ButtonSet.OK);
}
}
function openDialog() {
var ui = SlidesApp.getUi();
var html = 'link<input type="button" value="ok" onClick="ok()"><input type="button" value="cancel" onClick="cancel()"><script>function ok() {google.script.run.withSuccessHandler(()=>google.script.host.close()).setProp()}function cancel() {google.script.host.close()}</script>';
ui.showModalDialog(HtmlService.createHtmlOutput(html), "sample");
}
function setProp() {
var keyObject = {key1: "value1"};
var prop = PropertiesService.getUserProperties();
prop.setProperties(keyObject);
}
In this case, the URL can be clicked. But in order to open the custom dialog, it is required to open it from the custom menu. I think that this is the limitation when this workaround is used.
Note:
Above scripts are the simple scripts for testing the workaround. So please modify them for your actual situation.
References:
Simple Triggers
Installable Triggers
Alert dialogs
Custom dialogs
If I misunderstood your question and this was not the direction you want, I apologize.

Display Form in Sidebar

I am not sure if what I am trying to do is even possible.
I am trying to put a google form into the sidebar of a google doc.
Right now I have an apps script document plugin that opens the sidebar fine, and I am able to open the form using var form = FormApp.openById('form_id');
But I don't know how to get a html object or blob from a form element that I could use to embed the form in the sidebar.
I also can't use iframes as those are disallowed.
While you can display a google form in a sidebar in a spreadsheet/document (see sample code below), there is one significant gotcha with it: the form does not work, i.e. you can't submit the form. Not sure exactly why, but my guess it is due to the sandbox restrictions and/or caja sanitization.
I suggest you code your own form using HTML and HTML Service (or UI Service) and show that in a sidebar. If you need you form to save the responses to a spreadsheet, you can also do that rather easily. See this for more on info and code samples of using forms in HTML Service and this for using forms in UI Service. Your server-side script can open a spreadsheet and write form values to it, if that's what you need to do.
Sample code for an Add-on to show Google Form in a Sidebar in Google Sheet:
NOTE: The form does not actually work - it does not submit when shown in a sidebar!
function showFormInSidebar() {
var form = FormApp.openById('YOUR-FORM-ID-HERE');
var formContent = UrlFetchApp.fetch(form.getPublishedUrl()).getContentText();
var ui = HtmlService.createHtmlOutput(formContent).setTitle("Google Form in Sidebar Example");
SpreadsheetApp.getUi().showSidebar(ui);
};
function onOpen(e) {
// Add this add-on to Add-ons menu
SpreadsheetApp.getUi().createAddonMenu()
.addItem('Show form', 'showFormInSidebar')
.addToUi();
};

The simplest way to open a new window to show an HTML or URL? [duplicate]

This question already has answers here:
Google Apps Script to open a URL
(6 answers)
Closed 2 years ago.
The simplest way to open a new window to show an HTML like this -
Arun Nagarajan said on this post
https://stackoverflow.com/posts/13272748/edit
-<a href='http://www.google.com' target='_blank'>Open in new window</a>-
I want to open a Link in my google document (no spreadsheet)
directely by menu or
by function !!
How to arrive with my script ?
function onOpen() {
// Add a menu with some items, some separators, and a sub-menu.
DocumentApp.getUi().createMenu('OAR')
.addItem('MAJ Date + OAR', 'test')
.addItem('MAJ Date Auto', 'testdate')
***.addItem('Accès Direct URL', 'href=/d/1udvLSpaZNgalg6NId JMJvkkw3i9oCaEKa-A_CAC79CYkvsZKD545dyZN/edit?')***
.addToUi();
}
If you want to open a new page , use the class Anchor in Google App Script.
https://developers.google.com/apps-script/reference/ui/anchor?hl=fr
Looks like google scripts can't (don't allow us to) open links.
However you can show a dialog instructing the user..
since the UiApp is depreciated you can only use HtmlService to create HtmlOutput object then pass it to the UI
var content= 'You must go Here'; //html as string
var html = HtmlService.createHtmlOutput(content); //the output is the HtmlOutput
DocumentApp.getUi().showModalDialog(html, 'your_title');
or use DocumentApp.getUi().showModelessDialog(..., ...) if you don't want to prevent interaction with the document
and this will show the dialog with the wanted link
Check out this question
Google Apps Script to open a URL
I think this will help you, with only JS.
In parameter you can put the url you want as a string.
window.open(url);

Google App Script WebApp, Manipulating UI

Hi and Good day to all,
Google App Script can be used in so many ways. I know cause I have tried some of them but Iam not an expert so, the situation is.
I have created an Spreadsheet
create a form using the new UI Building that comes with the script editor.
named:gtest01
UI compose of:
label, id=label_caption
button 1, id=button_hide, event-onmouseclick=hide_label
button 2, id=button_show, event-onmouseclick=show_label
button 3, id=button_message, event-onmouseclick=message_me
now, the code is:
/* This is so when I want to just deploy it as a [webapp] using the
script editor -> Publish Deploy as Web App
*/
function doGet(e) {
var app = UiApp.createApplication().setTitle("Sheet Application");
app.add(app.loadComponent("gtest01"));
Logger.log("Application UI Loaded");
return app;
}
function message_me(e) {
Browser.msgBox("my message");
}
function hide_label(e) {
var app = UiApp.getActiveApplication();
label =app.getElementById("label_caption");
label.setVisible(false);
}
function show_label(e) {
var app = UiApp.getActiveApplication();
label =app.getElementById("label_caption");
label.setVisible(true);
}
// this code is for when the spreadsheet is shared so they can access the form
function showform_() {
var app = UiApp.createApplication();
app.add(app.loadComponent("gtest01"));
SpreadsheetApp.getActiveSpreadsheet().show(app);
}
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
menuEntries.push({name: "Show Form", functionName: "showform_"});
ss.addMenu("e-Test", menuEntries);
}
First scenario is that when spreadsheet is shared
when menu is clicked the form will load - thats good
when show and hide button nothing happens - why and how can i fixed
this?
when message button is click - message will show but the form will
close, how can I display a message without closing the form?
Second scenario is that when publish as Webapp.
When Developer Link is Access the UI is always updated - ok
When URL Link is Access the UI is always updated its like it is
cache, how can I fixed this?
on dev link: when show and hide button nothing happens - why and how
can i fixed this?
on dev link: when message button is click - will generate an error,
how can I display an alert message on WebApp
Please help I have search and tried the sample codes and answer in the forum am missing something.
Thanks
Nick Ace
First scenario
when show and hide button nothing happens - why and how can i fixed this?
In your functions, use return app at the end. Unless you return the app object, the UI doesn't get updated.
how can I display a message without closing the form? - Try
SpreadsheetApp.getActiveSpreadsheet().toast()
2nd scenario
When URL Link is Access the UI is always updated its like it is cache, how can I fixed this? - Save your most recent code as a version
on dev link: when show and hide button nothing happens - Again return app will take care of this
on dev link: when message button is click... - Browser.msgBox is not supported in a web app.
When Using UI it is generally a good idea to make everything happen inside this Ui, so try to avoid showing messages with Toast( as they are not supported in web apps anyway).
Since you are using the GUI it should be quite easy to use a label with your message that is initially invisible and to make it visible in an handler routine.
Note that this kind of handler can be a client handler as well unless you need to do something else from this action.
As for the other points of you question, our (very fast) friend Srik has already answered thoroughly ;-)