So using Google Apps Scripts with a Form, I'm able to get all the items and iterate through them using the following:
var form = FormApp.getActiveForm();
var items = form.getItems();
var item;
for(var i = 0; i < items.length; i++)
{
item = items[i];
if(item.getType() == FormApp.ItemType.DATE)
{
item = item.asDateItem();
item.dropdown.month; // I need a method like this
}
Logger.log("ItemTitle: %s ItemType: %s",items[i].getTitle(), items[i].getType()) ;
}
I can even get the DateItem that I want.
My issue is that I cannot get the dropdown boxes from the DateItem. Does anyone know how to get the dropdown boxes from the DateItem? (Like: item.dropdown.month or item.dropdown.day, etc).
FormApp describes the questions you're asking, not the answers received from people who filled the form out. The type of question is "when were you born?" - nobody answered it yet - there's no date available.
When the form submits, its results go into a spreadsheet. Write a script that parses the spreadsheet's content.
For this kind of dynamic form behavior (a form that responds live as users fill it out), your best bet is to build and HTML user interface using the HTMLService: https://developers.google.com/apps-script/guides/html/
This is significantly more complicated than working with the FormApp Class, but is much more powerful, and eventually allows you to deploy your code as a web app, or publish as an add-on for Sheets, Docs, or Forms.
Related
I have a Google Slide doc that has linked Google Sheets cells in it. This is not a linked chart. There is plenty of documentation out there on how to auto-refresh charts as the code below:
function createTrigger() {
// Trigger every 5 minute
ScriptApp.newTrigger('updateSheets')
.timeBased()
.everyMinutes(1)
.create();
}
/*
* Update all charts in the presentation
* Use trigger (minutes or hours)
*/
function updateSheets(){
var gotSlides = SlidesApp.getActivePresentation().getSlides();
for (var i = 0; i < gotSlides.length; i++) {
var slide = gotSlides[i];
var sheetsCharts = slide.getSheetsCharts();
for (var k = 0; k < sheetsCharts.length; k++) {
var shChart = sheetsCharts[k];
shChart.refresh();
}
}
}
This works fine if you are able to put cells of the sheet into a "table chart" for importing to Slides, but I would like to keep the formatting I have set up in the sheet itself and not have the added step of the table chart. The table shown in blue "Lathes" is what I have been trying to get to auto-refresh on time or on edit. What I would like to be able to do is copy and paste the cells directly into my presentation so that the formatting remains what I have specified and not what the "table chart" built in formatting is. The update all button in the linked items tab of the Google Slides app will update the linked cells but I have yet to find a Google App Script command to do the same.
Chart shown highlighted that mimics data in A4-C10. I am able to auto update this chart if put into a slides doc with the given code.
I would basically like to be able to have a script run the same function that is triggered when the "update all" button is pressed in the linked items tab.
Any help with this would be much appreciated.
Unfortunately so far it is not possible to refresh linked tables with the API
It certainly would be a useful feature, indeed there is already a feature request for it on Google's Public Issue Tracker.
I recommend you to "star" it to increase visibility and stay updated about its implementation.
I am creating a Quiz.
What I did first is to create data in google sheet and here it is
Link of Google Sheet
as you can see there I have 2 sheet and that is Questions and Answers
My Question is how can i display the Question and Answers in there respective position in Google Forms i am linking them by Question ID
TYSM
I think the comments above will help you. This is also code (with help from here) which copies a multiple-choice question from one quiz to another.
If you combine this code with the stuff referred to in the comments about reading stuff from a sheet then you should be ok.
I see that you mention a problem copying images. I'm stuck at that point too.
function copyMultipleChoiceItem(item1, item2) {
// copies MC question item1 to item2 - tested PDW 17/05/20
// copy of feedback now working - tested PDW 17/05/30
//
var item1MC = item1.asMultipleChoiceItem();
// basic question items
item2.setTitle(item1.getTitle());
item2.setHelpText(item1.getHelpText());
item2.setPoints(item1MC.getPoints());
item2.setRequired(item1MC.isRequired());
// the choices
var choices = item1MC.getChoices();
for (var i = 0; i < choices.length; i++) {
item2.createChoice(choices[i].getValue(),choices[i].isCorrectAnswer());
}
item2.setChoices(choices);
// the feedback
var feedback1 = item1MC.getFeedbackForCorrect();
item2.setFeedbackForCorrect(feedback1);
var feedback1 = item1MC.getFeedbackForIncorrect();
item2.setFeedbackForIncorrect(feedback1);
}
I'm not fully cleared about your question, but If you want an easy way to do a relationship between Google Sheets (columns) and Google Forms Drop-down lists and other Forms objects, you can try this add-on: formRange. Build your sheets then go to your Form and Addons. Chose formRange and install it. It's pretty easy to use and you have a little tutorial inside it.
formRanger: Google Form addon
This question already has answers here:
Google Apps Script to open a URL
(6 answers)
Closed 2 years ago.
I've created a spreadsheet in google drive, and I've put together a tutorial presentation using google presentations to demonstrate to the users how to use the spreadsheet and why it's better than the way we were doing it before.
What I would like is a message box to appear when the spreadsheet is opened asking if that person has watched the tutorial presentation yet. If the user clicks No I'd like to either open a new page in the browser to show them the presentation I've published, or show the presentation in a custom UI.
I've searched for hours and can't figure it out. Is this possible? Thank you for your help!
I'm new to the forum so please let me know if I posted this wrong. Thanks!
Something like this does it pretty well.
I used a fake button to keep the "look and feel" consistent with the other button , I simply added the link invisible on top of it ;-)
function alertLink() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle('Message').setHeight('100').setWidth('400');
var panel = app.createVerticalPanel().add(app.createHTML('Did you see my beautiful <b>Tutorial</b> ?'));
var grid = app.createGrid(1,2).setWidth('400');
var closeHandler = app.createServerHandler('close');
var b1 = app.createButton("NO and I'd like to").setTitle('go to the tutorial in a new tab');
var b2 = app.createButton("YES and I don't want to see it again",closeHandler).setTitle('close this window');
var link = app.createAnchor('XXXXXXXXXX','http://www.google.com').setStyleAttributes({'zIndex':'1' , 'position':'fixed' , 'top':'25' , 'left':'20', 'color':'transparent' }).setTitle('go to the tutorial in a new tab');
var G1 = app.createVerticalPanel().add(b1).add(link);
grid.setWidget(0,0,G1).setWidget(0,1,b2);
app.add(panel).add(grid)
doc.show(app)
}
function close(){
return UiApp.getActiveApplication().close();
}
Just use an onOpen trigger if you want it to execute automatically on spreadsheet open. (or rename the main function as onOpen() )
Here is how it looks like :
For an onOpen trigger, it's certainly a better UX to prompt the user with a dialog box offering the option to open a URL, as opposed to opening the URl automatically. See serge's answer here for how to do that (which is more up-to-date than the deprecated code in his answer on this thread).
But for other triggers (such as a menu item click) check out my answer here to open a URL automatically.
I developed a script extension that uses a Google doc as template AND as script holder.
It gives me a very nice environment to implement a mail merge application (see below).
At some point I use the DocsList class makeCopy(new Name) to generate all the docs that will be modified and sent. It goes simply like that :
var docId=docById.makeCopy('doc_'+Utilities.formatString("%03d",d)).getId();
Everything works quite nicely but (of course) each copy of the template doc contains a copy of the script which is obviously not necessary ! It is also a bit annoying since each time I open a copy to check if data are right I get the sidebar menu that opens automatically which is a time consuming process ...
My question is (are) :
is there any way to remove the embedded script from the copy ? (that would be simple)
or should I copy all the doc elements from the template to an empty document ? (which is also a possible way to go but I didn't try and I don't know what will be in this doc in real life use...
Shall I get a perfect clone in any case ?)
I've read the doc and didn't find any relevant clue but who knows ? maybe I missed something obvious ;-)
below is a reduced screen capture to show the context of this question :
Following Henrique's suggestion I used a workaround that prevents the UI to load on newly created documents... (thanks Henrique, that was smart ;-)
The function that is called by onOpen now goes like that :
function showFields() {
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var find = body.findText('#'); // the new docs have no field markers anymore.
if(find != null){ // show the UI only if markers are present in the document.
var html = HtmlService.createHtmlOutputFromFile('index')
.setTitle("Outils de l'option Publipostage").setWidth(370);
ui.showSidebar(html);
}
}
I have a submit button whose enablement state depends on several other widgets' state; and I can't come up with a client side solution in Google Apps Script to do the validation.
For example, take three checkboxes. The submit button should be enabled iff (if-and-only-if) at least one checkbox is enabled.
I know I could do this with server side validation but there shouldn't be any need for something this simple. Any suggestions? Thanks.
It perfectly possible to write client side handlers that depend on multiple widgets' states, as you can just chain many validateX calls on a single handler. The problem here is just that clientHandlers cannot validate checkboxes state.
I have opened an issue regarding this problem, you may want to star it to keep track of updates and kind of vote for it:
Issue 2220: UiApp handler validateValue of checkbox
Anyway, it is possible to workaround this, and I'll just to show you that it is possible to have handlers depending on multiple widgets value, but this code will be much simpler when issue 2220 is solved:
function doGet(e) {
var app = UiApp.createApplication().setTitle('Checkbox Test');
var panel = app.createVerticalPanel(),
noChecked = app.createClientHandler(),
button = app.createButton('Test').setEnabled(false);
for( var i = 0; i < 3; ++i ) {
var cb1 = app.createCheckBox('cb'+i),
cb2 = app.createCheckBox('cb'+i).setVisible(false),
tb = app.createTextBox().setValue('false').setVisible(false);
cb1.addClickHandler(app.createClientHandler().forTargets(cb2).setValue(true).setVisible(true).forEventSource().setVisible(false).forTargets(tb).setText('true'));
cb2.addClickHandler(app.createClientHandler().forTargets(cb1).setValue(false).setVisible(true).forEventSource().setVisible(false).forTargets(tb).setText('false'));
cb1.addClickHandler(app.createClientHandler().forTargets(button).setEnabled(true));
cb2.addClickHandler(noChecked.validateMatches(tb,'false'));
panel.add(cb1).add(cb2).add(tb);
}
noChecked.forTargets(button).setEnabled(false);
return app.add(panel.add(button));
}
ClientHandlers are intentionally simple. You can do arbitrary code with ServerHandlers and the speed difference should be relatively small. Otherwise, yes, this is by design and if you need more complicated client logic you need to use HtmlService.
The tradeoff between UiApp and HtmlService related to how we guarantee that you can't serve malicious code from a script. UiApp code uses simple builder patterns that are limiting but definitely safe, while HtmlService uses complex sandboxing to achieve that goal, with tradeoffs of not working on older browsers and some other limitations.
This specific use case sounds workable in UiApp, if I understand you correctly. If you want an example of a show/hide button that flips, here is one:
function doGet() {
var app = UiApp.createApplication();
var label = app.createLabel("I am a toggleable widget").setVisible(false);
var show = app.createButton("show");
var hide = app.createButton("hide").setVisible(false);
show.addClickHandler(app.createClientHandler()
.forTargets(label, hide).setVisible(true).forTargets(show).setVisible(false));
hide.addClickHandler(app.createClientHandler()
.forTargets(label, hide).setVisible(false).forTargets(show).setVisible(true));
return app.add(show).add(hide).add(label);
}
Basically, use 2 buttons and flip the visibility of the button too.
Checkboxes are in fact validated - but it is their text that is validated, not their value:
var app = UiApp.createApplication();
var check = app.createCheckBox();
check.setText("foo").addClickHandler(
app.createServerHandler("clicked").validateMatches(check, "foo"));
return app.add(check);
The issue tracker request is reasonable though.