Créer une SideBar avec Google Apps Script

Google Sheets vous permet de créer et d'afficher une barre latérale personnalisée capable de communiquer avec la feuille.

Sur cette page vous découvrirez un exemple simple de barre latérale avec un formulaire qui enregistre le contact entré à la suite d'un tableau dans la feuille.

Pour l'exemple, ce formulaire pourra également être affiché sous la forme d'une boîte de dialogue personnalisée.

Vous pouvez copier ce document Google Sheets à partir de cette page.


Menu personnalisé

La première fonction de ce fichier ajoute un menu personnalisé qui vous permettra d'afficher au choix le formulaire dans la barre latérale ou dans une boîte de dialogue :

function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('Sheets-Pratique')
    .addItem('Formulaire (barre latérale)', 'formulaire')
    .addItem('Formulaire (boîte de dialogue)', 'formulaire2')
    .addItem('Formulaire (boîte de dialogue non bloquante)', 'formulaire3')
    .addToUi();
}

Aperçu :

google sheets menu custom sidebar

Barre latérale

La fonction formulaire affiche le formulaire dans la barre latérale :

function formulaire() {
  const html = HtmlService.createHtmlOutputFromFile('form').setTitle('Ajouter un utilisateur');
  SpreadsheetApp.getUi().showSidebar(html);
}

Aperçu :

google sheets sidebar formulaire png

Boîte de dialogue

La fonction formulaire2 permet d'afficher ce même formulaire mais cette fois-ci dans une boîte de dialogue :

function formulaire2() {
  const html = HtmlService.createHtmlOutputFromFile('form')
    .setWidth(300)
    .setHeight(485);
  SpreadsheetApp.getUi().showModalDialog(html, 'Ajouter un utilisateur');
}

Aperçu :

google sheets boite dialogue formulaire png sidebar

La fonction formulaire3 quant à elle affiche une boîte de dialogue "non bloquante" (qui permet par exemple de modifier les cellules tout en ayant la boîte de dialogue ouverte) :

function formulaire3() {
  const html = HtmlService.createHtmlOutputFromFile('form')
    .setWidth(300)
    .setHeight(485);
  SpreadsheetApp.getUi().showModelessDialog(html, 'Ajouter un utilisateur');
}

Aperçu :

google sheets boite dialogue formulaire showmodelessmialog png sidebar

HTML

Le code HTML de ce formulaire (sans style, ni script) est le suivant :

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <p>Nom</p>
    <input type="text" name="nom" value="">
    <p>Prénom</p>
    <input type="text" name="prenom" value="">
    <p>Adresse</p>
    <input type="text" name="adresse" value="">
    <p>Code postal</p>
    <input type="text" name="code_postal" value="">
    <p>Ville</p>
    <input type="text" name="ville" value="">
    <input type="button" value="Ajouter" onclick="ajouter()">
    <span class="annuler" onclick="google.script.host.close()">Annuler</span>
  </body>
</html>

Il est composé de paragraphes :

<p>Nom</p>

De champs textes :

<input type="text" name="nom" value="">

D'un bouton qui exécute la fonction ajouter au clic :

<input type="button" value="Ajouter" onclick="ajouter()">

Et d'un "lien" Annuler qui ferme la fenêtre au clic :

<span class="annuler" onclick="google.script.host.close()">Annuler</span>

JavaScript

Le code JavaScript de ce formulaire (inséré entre les balises script) contient la fonction ajouter qui est déclenchée au clic sur le bouton :

<script>
  function ajouter() {
    const inputs = document.querySelectorAll('input[type="text"]');
    let tab = [];

    // Récupération des valeurs
    for (const input of inputs) {
      tab.push(input.value);
    }

    // Si tous les champs sont vides
    if (tab.join('') == '') {
      alert('Le formulaire est vide !');
      return;
    }

    // Vider les champs
    inputs.forEach(input => input.value = '');

    // Envoi dans la feuille
    google.script.run.ajouterLigne(tab);
  }
</script>

La fonction commence par récupérer les champs textes de la page :

const inputs = document.querySelectorAll('input[type="text"]');

Elle récupère ensuite les valeurs de ces champs et les ajoute dans le tableau tab :

for (const input of inputs) {
  tab.push(input.value);
}

Pour éviter d'insérer une ligne vide, la fonction vérifie s'il y a au moins un champ non vide et s'arrête là si ce n'est pas le cas :

if (tab.join('') == '') {
  alert('Le formulaire est vide !');
  return;
}

Les champs sont ensuite vidés (pour le prochain ajout) :

inputs.forEach(input => input.value = '');

Et la fonction ajouterLigne (Apps Script) est exécutée, avec le tableau contenant les valeurs des champs passé en argument :

google.script.run.ajouterLigne(tab);

Apps Script

La fonction ajouterLigne insère les données passées en argument à la suite des contacts dans la feuille :

function ajouterLigne(tab) {
  SpreadsheetApp.getActiveSheet().appendRow(tab);
}

Codes complets

Pour terminer, voici le code Apps Script au complet :

// Menu personnalisé
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('Sheets-Pratique')
    .addItem('Formulaire (barre latérale)', 'formulaire')
    .addItem('Formulaire (boîte de dialogue)', 'formulaire2')
    .addItem('Formulaire (boîte de dialogue non bloquante)', 'formulaire3')
    .addToUi();
}

// Barre latérale
function formulaire() {
  const html = HtmlService.createHtmlOutputFromFile('form').setTitle('Ajouter un utilisateur');
  SpreadsheetApp.getUi().showSidebar(html);
}

// Boîte de dialogue
function formulaire2() {
  const html = HtmlService.createHtmlOutputFromFile('form')
    .setWidth(300)
    .setHeight(485);
  SpreadsheetApp.getUi().showModalDialog(html, 'Ajouter un utilisateur');
}

// Boîte de dialogue (showModelessDialog)
function formulaire3() {
  const html = HtmlService.createHtmlOutputFromFile('form')
    .setWidth(300)
    .setHeight(485);
  SpreadsheetApp.getUi().showModelessDialog(html, 'Ajouter un utilisateur');
}

// Insertion des données du formulaire
function ajouterLigne(tab) {
  SpreadsheetApp.getActiveSheet().appendRow(tab);
}

Ainsi que la page HTML form au complet :

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        padding: 0 0.5rem; /* à remplacer par "margin: 0;" si affiché dans une boîte de dialogue */
        color: #333;
        font-family: Roboto, Arial, sans-serif;
        overflow: hidden;
      }
      p {
        margin: 0.8rem 0 0.3rem;
      }
      .annuler {
        display: inline-block;
        margin-top: 1rem;
        font-size: 0.88rem;
        color: #888;
        cursor: pointer;
      }
      .annuler:hover {
        text-decoration: underline;
      }
      input[type="text"] {
        display: block;
        width: 100%;
        box-sizing: border-box;
        margin-bottom: 1rem;
        padding: 0.6rem 0.7rem;
        background: #f3f3f3;
        color: #444;
        border: none;
        font-size: 1.08rem;
        border-radius: 0.4rem;
      }
      input[type="button"] {
        display: block;
        width: 100%;
        padding: 0.7rem 0 0.6rem;
        border: none;
        background: #30a392;
        color: #fff;
        font-size: 1.15rem;
        cursor: pointer;
        border-radius: 0.4rem;
      }
      input[type="button"]:hover {
        background: #40ad96;
      }
    </style>
  </head>
  <body>
    <p>Nom</p>
    <input type="text" name="nom" value="">
    <p>Prénom</p>
    <input type="text" name="prenom" value="">
    <p>Adresse</p>
    <input type="text" name="adresse" value="">
    <p>Code postal</p>
    <input type="text" name="code_postal" value="">
    <p>Ville</p>
    <input type="text" name="ville" value="">
    <input type="button" value="Ajouter" onclick="ajouter()">
    <span class="annuler" onclick="google.script.host.close()">Annuler</span>
    <script>
      function ajouter() {
        const inputs = document.querySelectorAll('input[type="text"]');
        let tab = [];

        // Récupération des valeurs
        for (const input of inputs) {
          tab.push(input.value);
        }

        // Si tous les champs sont vides
        if (tab.join('') == '') {
          alert('Le formulaire est vide !');
          return;
        }

        // Vider les champs
        inputs.forEach(input => input.value = '');

        // Envoi dans la feuille
        google.script.run.ajouterLigne(tab);
      }
    </script>
  </body>
</html>

CSS

Pour mieux comprendre les règles de style CSS, voici quelques commentaires en bonus :

body {
  padding: 0 0.5rem; /* marges intérieures */
  color: #333; /* couleur du texte */
  font-family: Roboto, Arial, sans-serif; /* police */
  overflow: hidden; /* masque ici la barre de défilement verticale des boîtes de dialogue */
}
p {
  margin: 0.8rem 0 0.3rem; /* marges */
}
.annuler {
  display: inline-block; 
  margin-top: 1rem; /* marge en haut */
  font-size: 0.88rem; /* taille du texte */
  color: #888; /* couleur du texte */
  cursor: pointer; /* curseur main */
}
.annuler:hover { /* hover = au survol */
  text-decoration: underline; /* texte souligné */
}
input[type="text"] {
  display: block;
  width: 100%; /* largeur à 100% */
  box-sizing: border-box; /* pour tenir compte des marges dans le calcul de la largeur */
  margin-bottom: 1rem; /* marge en bas */
  padding: 0.6rem 0.7rem; /* marges intérieures */
  background: #f3f3f3; /* couleur de fond */
  color: #444; /* couleur du texte */
  border: none; /* pas de bordures */
  font-size: 1.08rem; /* taille du texte */
  border-radius: 0.4rem; /* bords arrondis */
}
input[type="button"] {
  display: block;
  width: 100%; /* largeur à 100% */
  padding: 0.7rem 0 0.6rem; /* marges intérieures */
  border: none; /* pas de bordures */
  background: #30a392; /* couleur de fond */
  color: #fff; /* couleur du texte */
  font-size: 1.15rem; /* taille du texte */
  cursor: pointer; /* curseur main */
  border-radius: 0.4rem; /* bords arrondis */
}
input[type="button"]:hover { /* hover = au survol */
  background: #40ad96; /* couleur de fond */
}