11217 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous!
je travaille sur un script google dont l'objectif est de compléter des listes déroulantes dans des formulaires à l'aide des données contenues dans un classeur gsheet (il s'agit en l'occurrence de listes de classes).
Mes contraintes sont les suivantes:
- à chaque classe correspond une feuille du classeur,
- à chaque classe doit correspondre un formulaire indépendant (à part cela, ils ont tous la même structure et la liste déroulante avec les noms et prénoms est le premier item du formulaire),
- tous les formulaires sont contenus dans le même dossier sur Google Drive.

Je pourrais faire un script par formulaire et par classe. Mais le nombre de classes peut varier selon les années et je n'ai pas envie de remettre les mains dans le cambouis sans arrêt.

Voici où j'en suis:
- j'ai réussi à faire un script qui recense tous les formulaires présents dans le dossier-cible, qui récupère leur nom et leur ID (dans le drive de Google, chaque fichier ou dossier est identifié par un ID unique) et qui stocke ces données dans un array.
- j'ai réussi à ajouter un script qui, pour une ligne précise de l'array, sélectionne la feuille correspondante du classeur gsheet et remplit la liste déroulante avec les noms des élèves de la classe-cible.

Maintenant il faut que je puisse faire la même chose pour chaque ligne de l'array. J'ai pensé à une boucle while, mais cela ne marche pas: pas d'erreur de syntaxe (la console ne renvoie aucun bug) mais aucun effet! C'est la première fois que je fais un script aussi complexe (pour mon niveau), et je n'arrive pas à voir où est le bug. Voici le code de la boucle en question:


var fileList = list.sort(); //dans cette variable se trouvent les noms et ID de tous les formulaires dont j'ai besoin sous forme d'un array à deux colonnes: [Nom, ID]. 
//Si je log fileList, j'ai bien ma liste de formulaires au complet.


  while (fileList.hasNext){
    var list = fileList.next();
      Logger.log (list) //quand je log la variable list, je n'obtiens rien!
    var formId = file[0][1]; //ici on récupère l'ID qui servira à ouvrir le bon formulaire (premier crochet = ligne, à itérer, 2e crochet = colonne à ne surtout pas modifier)

    //récupération du titre du formulaire pour trouver automatiquement le nom de la feuille contenant la liste de classe voulue (nécessite une stricte correspondance du titre du formulaire et de la feuille)
    var formTitle = FormApp.openById(formId).getTitle();
 
        //ouverture du classeur dont j'ai récupéré l'ID au début du script
    var wsData = SpreadsheetApp.openById(ssId).getSheetByName(formTitle);
    //ouverture du formulaire de la classe
    var form = FormApp.openById(formId);

  //variable stockant le nom des élèves dans un tableau
    var options = wsData
                        .getRange(2, 1,wsData.getLastRow()-1, 1)
                        .getValues()
                        .map(function (o){return o[0]}); 
    
  
    //récupération de l'identifiant de la liste déroulante et établissement de la liste de choix selon le contenu de la variable "options"  
    var chercheitemID = form.getItems()
    var itemId = chercheitemID[0].getId().toString();

    for (var i=0;i<fileList.length;i++){
      var item = form.getItemById(itemId);
        item.asListItem().setChoiceValues(options);}
  };


Merci d'avance pour vos conseils!
Modifié par bouffandt (08 Dec 2021 - 08:43)
Petit édit de mon message précédent: j'ai remplacé la boucle while par une boucle for:

  var fileList = list.sort(); //on trie le tableau par ordre croissant de noms
  Logger.log(fileList)
  
  for (var i=0;i<fileList.length;i++){
     var formId = fileList[i][1]; //ici on récupère l'ID qui servira à ouvrir le bon formulaire (premier crochet = ligne, à itérer, 2e crochet = colonne contenant l'ID du formulaire)
    //récupération du titre du formulaire pour trouver automatiquement le nom de la feuille contenant la liste de classe voulue (nécessite une stricte correspondance du titre du formulaire et de la feuille)
    var formTitle = FormApp.openById(formId).getTitle();
    Logger.log(formId)
 
        //ouverture du classeur
    var wsData = SpreadsheetApp.openById(ssId).getSheetByName(formTitle);
    //ouverture du formulaire de la classe
    var form = FormApp.openById(formId);

  //variable stockant le nom des élèves dans un tableau
    var options = wsData
                        .getRange(2, 1,wsData.getLastRow()-1, 1) 
                        .getValues() 
                        .map(function (o){return o[0]}); 
  
    //récupération de l'identifiant de la liste déroulante et établissement de la liste de choix selon le contenu de la variable "options"  
    var chercheitemID = form.getItems()
    var itemId = chercheitemID[0].getId().toString();
    var item = form.getItemById(itemId);
        item.asListItem().setChoiceValues(options);};
};

Cette fois-ci le script va bien itérer sur chaque ligne de mon tableau! Mais il reste un dernier problème au niveau de ce bout de script:

    //récupération de l'identifiant de la liste déroulante et établissement de la liste de choix selon le contenu de la variable "options"  
    var chercheitemID = form.getItems()
    var itemId = chercheitemID[0].getId().toString();
    var item = form.getItemById(itemId);
        item.asListItem().setChoiceValues(options);

Je reçois le message d'erreur "questions cannot have duplicate choice values" qui porte sur la dernière ligne de ce bout de code.
Modifié par bouffandt (08 Dec 2021 - 09:43)
Salut,

pour ton premier code, hasnext c'est une fonction, du coup il manquait les () .
Et ensuite il faut lire la doc javascript pour savoir si c'est applicable parce que de mémoire ce n'est pas utilisable sur n'importe quel type d'élément (il faut un Iterator je crois mais a confirmer par la doc)

Pour la 2e question, la structure m'a l'air bizarre. Si je comprends bien :
- Tu récupères plusieurs items dans un tableau
- Tu récupères l'id du 1er élément du tableau
- Tu re récupères ce même item (??) mais plus dans un tableau en passant par l'ID
- Tu fais un truc sur cette item.

Cela doit pouvoir se faire directement en un coup en skippant les id et en travaillant sur le 1er element de ton tableau non ?
Un truc du genre je dirais :

form.getItems()[0].asListItem().setChoiceValues(options);


Et par rapport à ton message d'erreur, je suppose que à un moment donnée ta boucle re écrase le même item et lui refait un setChoiceValues avec la même valeur que la première fois. Cela doit pouvoir se régler en vérifiant que les options que tu mets dans le setChoiceValues ne sont pas déjà présente dans l'item.
Meilleure solution
Bonjour et merci pour ta réponse,

Mathieuu a écrit :
la structure m'a l'air bizarre.

effectivement ce script a été élaboré en plusieurs phases et il se peut que je n'aie pas pris le chemin le plus simple pour arriver à mon but!

Mathieuu a écrit :
Et par rapport à ton message d'erreur, je suppose que à un moment donnée ta boucle re écrase le même item et lui refait un setChoiceValues avec la même valeur que la première fois. Cela doit pouvoir se régler en vérifiant que les options que tu mets dans le setChoiceValues ne sont pas déjà présente dans l'item.

Merci du conseil: cela m'a permis de trouver que le message d'erreur n'apparaît que si la nouvelle liste d'élève que je veux charger dans mon formulaire est identique à la précédente. Si il y a un changement dans la liste, ça passe. Il faudrait donc que je mette une condition if/else pour interrompre le script si deux listes sont identiques.
Modifié par bouffandt (09 Dec 2021 - 09:08)