Javascript, HTML, CSS e... !
5 commenti

Creare Form dinamici in modo programmatico

I vantaggi di creare un Google Form da codice tramite Google Apps Script

Un Google Form personalizzato è uno strumento molto utile per ottenere in modo rapido sondaggi e questionari da sottoporre agli utenti così come test di verifica con puteggio di valutazione per ogni esigenza (un corso online, un'assunzione, ecc...). La loro creazione da interfaccia web è semplice quanto creare un qualsiasi documento della Suite di Google e proprio grazie all'editor WYSIWYG dedicato diventa molto intuitivo andare a comporre le relative domande avvalendosi di diverse tipologia di elementi (risposta aperta, risposta multipla, caricamento di file, ecc...), ordinarle velocemente tramite drag & drop ed aggiungere placeholder ed altre opzioni disponibili, e tutto a portata di mouse.

La domanda che a questo punto vi starete facendo immagino che sia "allora perchè dovrei complicarmi la vita utilizzando Apps Script per creare un Google Form quando posso farlo in modo diretto e più semplice?".
La risposta che darei io è che sicuramente se le cose sono troppo semplici non sono neanche troppo divertenti ma al di là delle battute e delle visioni personali ci sono dei vantaggi che in taluni casi possono rivelarsi effettivamente tangibili ovvero, creando un Google Form con Google Apps Script (e quindi in maniera programmatica) è possibile dinamicizzare processi che permettono di cambiare le domande automaticamente ogni giorno, modificare il modulo per gli stessi o per i futuri intervistati in base alle risposte già fornite oppure aggiungere o rimuovere domande in base a qualsiasi parametro esterno (ad esempio l'ora del giorno, il giorno della settimana, la stagione, ecc...).

L'esempio che vado a presentare metterà in evidenza alcune chiamate ai metodi delle classi del Forms Service volti alla creazione di un sondaggio (nel caso specifico per la raccolta di informazioni sull'interesse sportivo da parte degli utenti) con diverse tipologie di domande ed opzioni attivate.

Il codice in questione è il seguente:

// Funzioni globali per il recupero dell'id dello Spreadsheet dove sono salvate le risposte al Form
var scriptProperties = PropertiesService.getScriptProperties();
var ssId = scriptProperties.getProperty('ssId');

// Nel caso lo Spreadsheet non esistesse ne viene creato uno
if (ssId == null) {
  var ss = SpreadsheetApp.create('Spreadsheet con le risposte al form');
  ssId = ss.getId();
  scriptProperties.setProperty('ssId',ssId);
}

function createForm() {

  // Se il Form esiste già non ne sarà creato un altro e l'esecuzione si ferma
  var formID = scriptProperties.getProperty('formId');
  if(formID != null) {
    throw('Attenzione! Il Form è già esistente.');
    return;
  }

  // Creazione di un Form vuoto
  var form = FormApp.create('Form creato programmaticamente');
  formID = form.getId();
  
  // Inserimento nel form di un campo di testo
  form.addTextItem()
  .setTitle('Scrivi il tuo nome e cognome?')
  .setHelpText('Inserisci il tuo nome e cognome')
  .setRequired(true);
  
  // Inserimento nel form di un selezionatore di date
  form.addDateItem()
  .setTitle('Qual è la tua data di nascita?')
  .setHelpText('Clicca sul tringolino rovesciato per aprire il selezionatore di data')
  .setRequired(true);
  
  // Inserimento nel form di un campo a scelta esclusiva
  form.addMultipleChoiceItem()
  .setTitle('Sesso')
  .setHelpText('Non sei obbligato a fornire questa informazione')
  .setChoiceValues(['M','F']);  
  
  // Inserimento nel form di un campo a scelta multipla
  var item = form.addCheckboxItem();
  item.setTitle('Dove preferisci allenarti?');
  item.setChoices([
    item.createChoice('Palestra'),
    item.createChoice('Piscina'),
    item.createChoice('Aria aperta'),
  ]);
  item.showOtherOption(true);
  
  // Inserimento nel form di un campo con griglia a scelta esclusiva su ogni riga
  form.addGridItem()
  .setTitle('In che misura sei interessato a ricevere promozioni sulle seguenti attività?')
  .setHelpText('Indica il tuo livello di interesse per ciascuna voce')
  .setRows(['Corsa', 'Nuoto', 'Ciclismo'])
  .setColumns(['non interessato', 'poco interessato', 'interessato', 'molto interessato']);
  
  // Assegnazione del Form allo Spreadsheet precedentemente creato
  form.setDestination(FormApp.DestinationType.SPREADSHEET, ssId);
  
  // Recupero delle informazioni del Form e loro scrittura in un foglio dello Spreadsheet
  scriptProperties.setProperty('formID',formID);
  ss.getSheets()[1].getRange(1,1,4,2).setValues(
    [
      ['Form Url', form.getPublishedUrl()],
      ['Form Edit Url', form.getEditUrl()],
      ['FormID', formID],
      ['Spreadsheet Url', ss.getUrl()]
    ]
  );
  ss.getSheets()[0].setColumnWidth(1,200).setColumnWidth(2,800);
}

function resetAllKeys(){
  // Azzera tutte le informazioni chiave-valore salvate a livello di script
  scriptProperties.deleteAllProperties();
}

Ed il risultato visivo del Form sarà questo (Fig. 1):



risultato di un google form creato con google apps script

Fig. 1 - Risultato di un Google Froms creato con Apps Script


E' importante premettere che i Form di Google si appoggiano ai fogli di calcolo della G Suite (meglio noti come Spreadsheet) sul quale saranno salvate le risposte fornite dagli utenti.
Scorporando lo script in diverse parti per andarle ad analizzare singolarmente possiamo distinguere le diverse operazioni tra le quali quelle designate ad effettuare una iniziale verifica, all'interno delle Properties dello script, della presenza o meno di un identificativo del Form (e di quello del relativo Spreadsheet) salvato, in caso positivo l'operazione viene bloccata (mostrando un messaggio personalizzato tramite throw) in quanto significa che esiste già un form creato con quelle caratteristiche evitandone così la sua duplicazione.
In caso invece di nuova effettiva generazione del form vengono eseguite tutta una serie di operazione finalizzate all'inserimento all'interno del documento delle varie domande che lo compongono:

var scriptProperties = PropertiesService.getScriptProperties();
var ssId = scriptProperties.getProperty('ssId');

if (ssId == null) {
  var ss = SpreadsheetApp.create('Spreadsheet con le risposte al form');
  ssId = ss.getId();
  scriptProperties.setProperty('ssId',ssId);
}

function createForm() {
  var formID = scriptProperties.getProperty('formId');
  if(formID != null) {
    throw('Attenzione! Il Form è già esistente.');
    return;
  }

  var form = FormApp.create('Form creato programmaticamente');
  formID = form.getId();
  // ...

Le domande possono essere di diverse tipologie, nel codice di esempio ne sono mostrate alcune e possiamo distinguere, nell'ordine, la creazione di un campo di testo (addTextItem) per l'immissione libera (ovvero in stile di domanda aperta) della risposta che, nel caso specifico, è il nome ed il cognome dell'utente, il campo prevede un titolo (setTitle), un testo di suggerimento (setHelpText) ed è impostato come obbligatorio (setRequired):

  form.addTextItem()
  .setTitle('Scrivi il tuo nome e cognome?')
  .setHelpText('Inserisci il tuo nome e cognome')
  .setRequired(true);

A seguire troviamo la creazione di un campo per l'immissione della data (addDateItem), per la richiesta della data di nascita, specificando anche per questo un titolo, un testo di suggerimento e l'obbligatorietà del dato per poter effettuare il submit del form:

  form.addDateItem()
  .setTitle('Qual è la tua data di nascita?')
  .setHelpText('Clicca sul tringolino rovesciato per aprire il selezionatore di data')
  .setRequired(true);

Il codice seguente (addMultipleChoiceItem) permette l'inserimento di una domanda, nel caso specifico sul sesso dell'utente, la cui risposta se fornita, dato che il campo non è stato impostato come obbligatorio, consente una scelta esclusiva (si tratta di quegli elementi che in HTML prendono il nome di radio button):

  form.addMultipleChoiceItem()
  .setTitle('Sesso')
  .setHelpText('Non sei obbligato a fornire questa informazione')
  .setChoiceValues(['M','F']); 

Successivamente si fa uso di un campo che prevede una scelta multipla (addCheckboxItem).
In questo caso viene mostrato un modo alternativo di richiamare (o meglio, scrivere il codice per richiamare) i metodi per l'elemento desiderato ovvero, anziché assegnarli tutti direttamente concatenati in sequenza (come appunto visto fino ad ora con i precedenti elementi), viene inserito il campo creato in un variabile (nel caso specifico chiamata item) ed ogni metodo viene richiamato signolarmente assegnandolo a questa variabile (niente di eclatante, ho solo mostrato un modo diverso per scrivere la stessa cosa).
Un'altra particolarità che emerge è l'uso del metodo showOtherOption(true) che aggiunge automaticamente un'opzione in fondo all'elenco delle opzioni indicate (chiamata 'Altro') permettendo l'inserimento manuale di un testo nel caso in cui nessuna delle precedenti proposte soddisfi la richiesta (tengo a precisare che la lingua dei testi inseriti in modo automatico da Google Form, come ad esempio l'opzione 'Altro' oppure i placeholder così come l'etichetta che indica i campi obbligatori, dipendono dalle impostazioni dell'account con il quale si apre il Form):

  var item = form.addCheckboxItem();
  item.setTitle('Dove preferisci allenarti?');
  item.setChoices([
    item.createChoice('Palestra'),
    item.createChoice('Piscina'),
    item.createChoice('Aria aperta'),
  ]);
  item.showOtherOption(true);

L'ultima domanda del form prevede una risposta in un formato a grigla (addGridItem) composto da righe e colonne definite consentendo di rispondere selezionando una sola opzione per ogni riga (ciascuna riga prevede una sequenza di radio button):

  form.addGridItem()
  .setTitle('In che misura sei interessato a ricevere promozioni sulle seguenti attività?')
  .setHelpText('Indica il tuo livello di interesse per ciascuna voce')
  .setRows(['Corsa', 'Nuoto', 'Ciclismo'])
  .setColumns(['non interessato', 'poco interessato', 'interessato', 'molto interessato']);

Viene poi impostato lo Spreadsheet creato precedentemente come destinazione delle risposte che gli utenti invieranno tramite il Google Form:

  form.setDestination(FormApp.DestinationType.SPREADSHEET, ssId);

Al termine della funzione ho inserito un utile riepilogo con le caratteristiche identificative del form (l'url di modifica, l'url di visualizzazione, il suo id) che verranno inserite in un foglio a se stante all'interno dello Spreadsheet precedentemente indicato (Fig. 2), in questo modo è sempre possibile, accedendo direttamente a tale foglio di calcolo di Google (soggetto ad essere maggiormente utilizzati rispetto al Form di per se in quanto contiene la parte utile del sistema, le risposte degli utenti), avere a portata di mano i link per risalire con immediatezza al relativo Google Form:

  scriptProperties.setProperty('formID',formID);
  ss.getSheets()[1].getRange(1,1,4,2).setValues(
    [
      ['Form Url', form.getPublishedUrl()],
      ['Form Edit Url', form.getEditUrl()],
      ['FormID', formID],
      ['Spreadsheet Url', ss.getUrl()]
    ]
  );
  ss.getSheets()[0].setColumnWidth(1,200).setColumnWidth(2,800);



identificativi del form salvati in un foglio dello spreadsheet delle risposte al form stesso

Fig. 2 - Identificativi del Google Form salvati in un foglio all'interno dello Spreadsheet delle risposte del relativo Form


Creando il Form (e lo Spreadsheet) facendo girare così come è il codice proposto in questo tutorial i file verranno creati nella root di Google Drive, se si intende modificare adeguatamente lo script al fine di creare i file in una cartella definita oppure nella cartella dove risiede il progetto Apps Script potete fare riferimento al mio articolo "Spostare i file tra le cartelle di Google Drive con Google Apps Script".

Ho inserito nello script un'ulteriore funzione che non ha niente a che vedere, direttamente, con la creazione di un Google Form in Apps Script ma che, tuttavia, può essere utile per l'esempio oggetto di questo tutorial dato che si fa uso delle PropertiesService per salvare delle coppie di dati chiave-valore a livello di script (l'id del Form e l'id dello Spreadsheet) nel caso volessimo svuotare queste informazioni per creare un nuovo form:

function resetAllKeys(){
  scriptProperties.deleteAllProperties();
}

Per approfondimenti su altre classi e metodi disponibili per la creazione, accesso e modifica dei Form di Google in modo dinamico rimando alla documentazione ufficiale del Forms Service di Google Apps Script.

Tags

Michele Pisani

Michele Pisani

Sviluppatore Javascript ed esperto in Digital Analytics

L'esperienza nel settore Digital Analytics unita ad anni di sviluppo in Javascript ha trovato la massima espressione in Google Apps Script che mi ha permesso, con estrema facilità e poche righe di codice, di realizzare potenti applicazioni interattive e processi automatizzati integrati con i prodotti della G Suite.

Come contattarmi
scrivi un commento

5 Commenti

  1. lunedì 24 settembre 2018 alle ore 09.20 Stefano

    Ciao Michele, in altro tutorial ho già espresso i complimenti per l'ottimo lavoro di formazione che stai facendo. Io appartengo alla categoria dei "neofiti" cioè di coloro che si stanno affacciando timidamente a questa tecnologia e che stanno sperimentando adesso i primi semplici tentativi. Ho fatto questa premessa perchè so già che la domanda che sto per farti è abbastanza "scema" e disarmante:
    come si fa a lanciare la tua funzione createForm()?
    Cioè qual'è l'evento che la renderà operativa?
    In altre parole, cosa si deve fare...creare un Form in bianco, con l'editor di questo form scrivere il tuo codice e poi...?
    Ti ringrazio per l'attenzione e per la...pazienza ;-)

    Rispondi a questo commento
    • lunedì 24 settembre 2018 alle ore 21.15 Michele PisaniAutore

      Ciao Stefano,
      il tutorial in questione mostra come sia possibile generare un Google Form direttamente da codice Apps Script.
      Per metterlo in pratica ti basta creare un nuovo file di script (di tipo autonomo) e copiarci il codice proposto nel tutorial, a quel punto eseguendo la funzione createForm() direttamente dall'editor di script (ed autorizzando lo script la prima volta che esegui una sua funzione), verrà generato un file di tipo Google Form nella root del tuo Drive.

      Ti suggerisco di iscriverti al gruppo Facebook Fatti di Apps Script: https://www.facebook.com/groups/AppsScript/
      In questo modo puoi ottenere supporto oltre che da me anche da altri utenti e per certi dubbi 'botta e risposta' è un canale più rapido.

      Rispondi a questo commento
  2. martedì 25 settembre 2018 alle ore 08.58 Stefano

    Iscrizione già fatta!
    Comunque grazie di nuovo per il tuo supporto e la tua attenzione...

    Rispondi a questo commento
  3. giovedì 13 dicembre 2018 alle ore 11.48 Luca

    ciao Michele,
    devo dire che le pagine che scrivi sono meravigliose.

    io sono molto basic in google script e programmazione, ma copiando e con tanta passione qualcosa di carino e soprattutto utile e funzionale per me l'ho creato.

    mi incuriosisce molto il tuo post perchè trovo che la dinamicità dei form sia un elemento importantissimo, se si vuole fare il passo verso un semplice database.

    in realtà vorrei chiederti se secondo te è possibile creare un form in cui si inserisce un valore (per esempio il nome cliente) e nella sezione successiva vengono caricati dei campi di scelta in funzione del nome fornito (dinamici)
    attualmente faccio questo usando combinando le cose (ho un foglio di sheets dove si scrive il nome e in funzione di quello viene fatto un Vlookup, e ho creato un tasto che, in base a quello che compare, reinvia a un link di forms precompilato con i dati che mi interessano)
    certo che questo ha un grosso difetto, ovvero che ci più lavorare solo 1 alla volta, e che comunque richiede un livello di risorse molto più elevato, non è fruibile da mobile....)

    siccome direi che, gestito in un solo form sia improbabile, forse si potrebbe fare in modo da crearlo come una sorta di 2 forms? il primo che invia i dati, e un attivatore on forms submit che apra un nuovo form con i dati "dinamici"?

    ogni suggerimento è apprezzato, e grazie in anticipo.
    Luca

    Rispondi a questo commento

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato.I campi contrassegnati da un * sono obbligatori
Puoi utilizzare i seguenti tag nei commenti:
[bold]testo[/bold] se vuoi evidenziare un testo con il grassetto[code]function helloworld() { }[/code] se vuoi pubblicare una porzione di codice[url]http://www.appsscript.it[/url] se devi riferirti ad un indirizzo web