Utiliser des chips de liste déroulante

L'API Google Docs vous permet de créer, d'insérer, de mettre à jour, de lire et de gérer des chips de menu déroulant de manière programmatique dans les documents Google Docs.

Que sont les chips de liste déroulante ?

Les chips de liste déroulante dans Google Docs offrent aux utilisateurs un menu de sélection interactif et personnalisable intégré au texte du document. Les utilisateurs peuvent cliquer sur un chip de liste déroulante pour sélectionner une option dans une liste prédéfinie. Chaque option possède son propre texte d'affichage et style de couleur. Les chips de liste déroulante sont fréquemment utilisés pour le suivi des projets, les mises à jour de l'état, les workflows de révision et les étapes d'approbation.

L'API Docs vous permet d'effectuer les opérations suivantes :

  • Définissez des modèles de menu déroulant réutilisables avec des titres, des noms d'options et des couleurs personnalisés.
  • Insérez des chips de liste déroulante à un emplacement de caractère valide.
  • Mettez à jour l'option sélectionnée d'une instance de chip de liste déroulante individuelle.
  • Modifiez les définitions de menus déroulants partagés sur place, en mettant à jour simultanément tous les chips de référence.
  • Remplacez ou retirez des options de manière sécurisée tout en conservant l'intégrité référentielle dans les chips existants.
  • Supprimez les modèles de menu déroulant inutilisés.

Architecture : définitions et instances

Dans l'API Docs, les chips de menu déroulant ont des définitions et des instances. Une définition définit les options d'une instance de menu déroulant. Une instance de menu déroulant est un menu déroulant avec lequel les utilisateurs peuvent interagir. Elle enregistre des informations sur les sélections.

L'API Docs sépare la configuration du modèle de menu déroulant des instances de chip de menu déroulant intégré :

  1. DropdownDefinition : modèle au niveau de l'onglet qui définit le titre du menu déroulant et la collection de choix sélectionnables (DropdownOption). Il ne réside pas à un décalage de caractère spécifique dans le document, mais est stocké dans le mappage de définition de l'onglet : document.tabs[].documentTab.dropdownDefinitions.
  2. Menu déroulant : instance de chip individuelle intégrée dans un élément de paragraphe (ParagraphElement.dropdown). Chaque instance de menu déroulant fait référence à un dropdownDefinitionId et stocke son propre selectedOptionId actif.

Si vous modifiez un DropdownDefinition (par exemple, en ajoutant une option ou en renommant le titre), tous les chips référencés dans l'onglet sont mis à jour sans que vous ayez à modifier chaque élément individuellement.

Chaque instance Dropdown suit son propre selectedOptionId. La modification de la valeur sélectionnée d'un chip individuel n'affecte que cette instance spécifique.

Format des ID et règles de validation

Les ID fournis par les utilisateurs doivent respecter des spécifications strictes en termes de format, de préfixe et de longueur :

Identifiant Préfixe obligatoire Expression régulière de validation Limite de longueur Exemple
ID de définition du menu déroulant (dropdownDefinitionId) kix. ^kix\.[a-zA-Z0-9_-]{2,14}$ 6 à 18 caractères kix.review_status
ID de l'option de menu déroulant (optionId) dropdownItem. ^dropdownItem\.[a-zA-Z0-9_-]{2,14}$ 15 à 27 caractères dropdownItem.pending

Générer des identifiants fournis par l'utilisateur

Pour générer des ID respectant les exigences obligatoires concernant le préfixe et l'expression régulière, utilisez les fonctions d'assistance suivantes. Ces helpers génèrent des suffixes alphanumériques en base 36 en minuscules, correspondant au format généré par l'interface utilisateur de Google Docs :

Python

import random
import string

def generate_dropdown_definition_id(suffix_len: int = 8) -> str:
    """Generates a valid user-provided DropdownDefinition ID (6-18 chars, starting with 'kix.')."""
    chars = string.ascii_lowercase + string.digits
    suffix = "".join(random.choices(chars, k=max(2, min(suffix_len, 14))))
    return f"kix.{suffix}"

def generate_dropdown_option_id(suffix_len: int = 8) -> str:
    """Generates a valid user-provided DropdownOption ID (15-27 chars, starting with 'dropdownItem.')."""
    chars = string.ascii_lowercase + string.digits
    suffix = "".join(random.choices(chars, k=max(2, min(suffix_len, 14))))
    return f"dropdownItem.{suffix}"

Java

import java.security.SecureRandom;

public final class DropdownIdGenerator {
  private static final String BASE36_CHARS =
      "abcdefghijklmnopqrstuvwxyz0123456789";
  private static final SecureRandom RANDOM = new SecureRandom();

  private DropdownIdGenerator() {}

  /** Generates a valid user-provided DropdownDefinition ID (6-18 chars, starting with "kix."). */
  public static String generateDefinitionId(int suffixLength) {
    int length = Math.max(2, Math.min(suffixLength, 14));
    StringBuilder sb = new StringBuilder("kix.");
    for (int i = 0; i < length; i++) {
      sb.append(BASE36_CHARS.charAt(RANDOM.nextInt(BASE36_CHARS.length())));
    }
    return sb.toString();
  }

  /** Generates a valid user-provided DropdownOption ID (15-27 chars, starting with "dropdownItem."). */
  public static String generateOptionId(int suffixLength) {
    int length = Math.max(2, Math.min(suffixLength, 14));
    StringBuilder sb = new StringBuilder("dropdownItem.");
    for (int i = 0; i < length; i++) {
      sb.append(BASE36_CHARS.charAt(RANDOM.nextInt(BASE36_CHARS.length())));
    }
    return sb.toString();
  }
}

Créer et insérer des chips de liste déroulante

Création d'un seul lot (recommandé)

Le modèle le plus efficace combine CreateDropdownDefinitionRequest et InsertDropdownRequest dans un seul appel documents.batchUpdate.

L'exemple de code suivant crée une définition de menu déroulant "État de l'examen" avec trois choix codés par couleur à l'aide d'ID fournis par l'utilisateur, et insère une instance à la fin du document :

Python

requests = [
    {
        "createDropdownDefinition": {
            "dropdownDefinition": {
                "dropdownDefinitionId": "kix.review_status",
                "dropdownDefinitionProperties": {
                    "title": "Review Status",
                    "options": [
                        {
                            "optionId": "dropdownItem.pending",
                            "displayValue": "Pending Review",
                            "textStyle": {
                                "backgroundColor": {
                                    "color": {"rgbColor": {"red": 0.99, "green": 0.90, "blue": 0.65}}
                                },
                                "foregroundColor": {
                                    "color": {"rgbColor": {"red": 0.45, "green": 0.30, "blue": 0.0}}
                                },
                            },
                        },
                        {
                            "optionId": "dropdownItem.approved",
                            "displayValue": "Approved",
                            "textStyle": {
                                "backgroundColor": {
                                    "color": {"rgbColor": {"red": 0.85, "green": 0.95, "blue": 0.85}}
                                },
                                "foregroundColor": {
                                    "color": {"rgbColor": {"red": 0.08, "green": 0.40, "blue": 0.15}}
                                },
                            },
                        },
                        {
                            "optionId": "dropdownItem.rejected",
                            "displayValue": "Needs Changes",
                            "textStyle": {
                                "backgroundColor": {
                                    "color": {"rgbColor": {"red": 0.98, "green": 0.84, "blue": 0.84}}
                                },
                                "foregroundColor": {
                                    "color": {"rgbColor": {"red": 0.65, "green": 0.10, "blue": 0.10}}
                                },
                            },
                        },
                    ],
                },
            }
        }
    },
    {
        "insertDropdown": {
            "endOfSegmentLocation": {},
            "dropdownDefinitionId": "kix.review_status",
            "selectedOptionId": "dropdownItem.pending",
        }
    },
]

result = service.documents().batchUpdate(
    documentId=DOCUMENT_ID,
    body={"requests": requests}
).execute()

Java

List<Request> requests = new ArrayList<>();

List<DropdownOption> options = Arrays.asList(
    new DropdownOption()
        .setOptionId("dropdownItem.pending")
        .setDisplayValue("Pending Review")
        .setTextStyle(new TextStyle()
            .setBackgroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.99f).setGreen(0.90f).setBlue(0.65f))))
            .setForegroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.45f).setGreen(0.30f).setBlue(0.0f))))),
    new DropdownOption()
        .setOptionId("dropdownItem.approved")
        .setDisplayValue("Approved")
        .setTextStyle(new TextStyle()
            .setBackgroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.85f).setGreen(0.95f).setBlue(0.85f))))
            .setForegroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.08f).setGreen(0.40f).setBlue(0.15f))))),
    new DropdownOption()
        .setOptionId("dropdownItem.rejected")
        .setDisplayValue("Needs Changes")
        .setTextStyle(new TextStyle()
            .setBackgroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.98f).setGreen(0.84f).setBlue(0.84f))))
            .setForegroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.65f).setGreen(0.10f).setBlue(0.10f))))));

DropdownDefinition definition = new DropdownDefinition()
    .setDropdownDefinitionId("kix.review_status")
    .setDropdownDefinitionProperties(new DropdownDefinitionProperties()
        .setTitle("Review Status")
        .setOptions(options));

requests.add(new Request().setCreateDropdownDefinition(
    new CreateDropdownDefinitionRequest().setDropdownDefinition(definition)));

requests.add(new Request().setInsertDropdown(
    new InsertDropdownRequest()
        .setEndOfSegmentLocation(new EndOfSegmentLocation())
        .setDropdownDefinitionId("kix.review_status")
        .setSelectedOptionId("dropdownItem.pending")));

BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest().setRequests(requests);
BatchUpdateDocumentResponse response = docsService.documents()
    .batchUpdate(DOCUMENT_ID, body)
    .execute();

Règles et limites de validation des menus déroulants

Lorsque vous créez ou modifiez des définitions de menu déroulant, les contraintes suivantes s'appliquent :

  • Nombre d'options : une définition de liste déroulante doit comporter entre 2 et 50 options.
  • Longueur du titre : la définition title ne peut pas être vide et ne doit pas dépasser 200 caractères.
  • Longueur de la valeur d'affichage : la displayValue de chaque option ne peut pas être vide et ne doit pas dépasser 200 caractères.
  • Style des options : seuls foregroundColor et backgroundColor sont acceptés dans DropdownOption.textStyle. La définition d'autres propriétés de style renvoie une erreur 400 Bad Request.
  • Sélection par défaut : dans InsertDropdownRequest, si selectedOptionId est omis, le chip est défini par défaut sur la première option définie dans DropdownDefinition.

Modifier la sélection d'un chip de liste déroulante individuel

Pour modifier l'option sélectionnée d'une instance de chip de liste déroulante existante sans modifier son modèle ni d'autres chips, utilisez UpdateDropdownPropertiesRequest :

  • dropdownId : (obligatoire) ID de l'instance de chip de liste déroulante spécifique à mettre à jour.
  • tabId : ID de l'onglet contenant le menu déroulant (par défaut, le premier onglet si omis).
  • Définissez fields sur "selectedOptionId".

L'exemple de code suivant met à jour la sélection active d'un chip de liste déroulante sur "dropdownItem.approved" :

Python

requests = [
    {
        "updateDropdownProperties": {
            "dropdownId": "kix.chip_abc1",
            "tabId": "t.0",
            "dropdownProperties": {
                "selectedOptionId": "dropdownItem.approved",
            },
            "fields": "selectedOptionId",
        }
    }
]

result = service.documents().batchUpdate(
    documentId=DOCUMENT_ID,
    body={"requests": requests}
).execute()

Java

List<Request> requests = new ArrayList<>();
requests.add(new Request().setUpdateDropdownProperties(
    new UpdateDropdownPropertiesRequest()
        .setDropdownId("kix.chip_abc1")
        .setTabId("t.0")
        .setDropdownProperties(new DropdownProperties()
            .setSelectedOptionId("dropdownItem.approved"))
        .setFields("selectedOptionId")));

BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest().setRequests(requests);
BatchUpdateDocumentResponse response = docsService.documents()
    .batchUpdate(DOCUMENT_ID, body)
    .execute();

Modifier les définitions et les options des menus déroulants

Pour modifier le modèle lui-même (titre, liste d'options, libellés ou couleurs), utilisez UpdateDropdownDefinitionPropertiesRequest. Si vous modifiez une définition, tous les chips de menu déroulant qui y font référence dans l'onglet sont automatiquement mis à jour.

Remplacement complet de la liste des options

Lorsque dropdownDefinitionProperties.options est inclus dans le masque fields, la requête effectue un remplacement complet de la liste. Vous devez fournir la liste complète des options dans l'ordre choisi. Le serveur compare la liste entrante à la définition actuelle :

  • Nouvelle option : l'ajout d'une option sans optionId (ou avec un nouveau optionId fourni par l'utilisateur) l'ajoute à la définition.
  • Option modifiée : si vous fournissez un optionId existant avec des displayValue ou textStyle modifiés, l'option est mise à jour sur place.
  • Options réorganisées : la liste des options est enregistrée dans l'ordre exact fourni dans la requête.
  • Option supprimée : si vous omettez un optionId existant, cette option sera supprimée de la définition.

Intégrité référentielle et remplacement des options

Si une option à supprimer est sélectionnée dans un chip de liste déroulante du document, vous devez fournir un mappage dans selectedOptionIdReplacements (map<string, string>). Les clés sont les ID des options à supprimer, et les valeurs sont les ID des options de remplacement.

L'exemple de code suivant montre comment mettre à jour une définition de menu déroulant avec des options de remplacement :

Python

requests = [
    {
        "updateDropdownDefinitionProperties": {
            "dropdownDefinitionId": "kix.review_status",
            "tabId": "t.0",
            "dropdownDefinitionProperties": {
                "title": "Editorial Review Status",
                "options": [
                    {
                        "optionId": "dropdownItem.approved",
                        "displayValue": "Approved",
                        "textStyle": {
                            "backgroundColor": {
                                "color": {"rgbColor": {"red": 0.85, "green": 0.95, "blue": 0.85}}
                            },
                            "foregroundColor": {
                                "color": {"rgbColor": {"red": 0.08, "green": 0.40, "blue": 0.15}}
                            },
                        },
                    },
                    {
                        "optionId": "dropdownItem.rejected",
                        "displayValue": "Changes Requested",
                        "textStyle": {
                            "backgroundColor": {
                                "color": {"rgbColor": {"red": 0.98, "green": 0.84, "blue": 0.84}}
                            },
                            "foregroundColor": {
                                "color": {"rgbColor": {"red": 0.65, "green": 0.10, "blue": 0.10}}
                            },
                        },
                    },
                ],
            },
            "selectedOptionIdReplacements": {
                "dropdownItem.pending": "dropdownItem.rejected"
            },
            "fields": "title,options",
        }
    }
]

result = service.documents().batchUpdate(
    documentId=DOCUMENT_ID,
    body={"requests": requests}
).execute()

Java

List<DropdownOption> updatedOptions = Arrays.asList(
    new DropdownOption()
        .setOptionId("dropdownItem.approved")
        .setDisplayValue("Approved")
        .setTextStyle(new TextStyle()
            .setBackgroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.85f).setGreen(0.95f).setBlue(0.85f))))
            .setForegroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.08f).setGreen(0.40f).setBlue(0.15f))))),
    new DropdownOption()
        .setOptionId("dropdownItem.rejected")
        .setDisplayValue("Changes Requested")
        .setTextStyle(new TextStyle()
            .setBackgroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.98f).setGreen(0.84f).setBlue(0.84f))))
            .setForegroundColor(new OptionalColor().setColor(
                new Color().setRgbColor(new RgbColor().setRed(0.65f).setGreen(0.10f).setBlue(0.10f))))));

Map<String, String> replacements = new HashMap<>();
replacements.put("dropdownItem.pending", "dropdownItem.rejected");

List<Request> requests = new ArrayList<>();
requests.add(new Request().setUpdateDropdownDefinitionProperties(
    new UpdateDropdownDefinitionPropertiesRequest()
        .setDropdownDefinitionId("kix.review_status")
        .setTabId("t.0")
        .setDropdownDefinitionProperties(new DropdownDefinitionProperties()
            .setTitle("Editorial Review Status")
            .setOptions(updatedOptions))
        .setSelectedOptionIdReplacements(replacements)
        .setFields("title,options")));

BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest().setRequests(requests);
BatchUpdateDocumentResponse response = docsService.documents()
    .batchUpdate(DOCUMENT_ID, body)
    .execute();

Supprimer une définition de menu déroulant

Pour supprimer un modèle de menu déroulant inutilisé, utilisez DeleteDropdownDefinitionRequest.

L'exemple de code suivant montre comment supprimer une définition de menu déroulant :

Python

requests = [
    {
        "deleteDropdownDefinition": {
            "dropdownDefinitionId": "kix.review_status",
            "tabId": "t.0",
        }
    }
]

result = service.documents().batchUpdate(
    documentId=DOCUMENT_ID,
    body={"requests": requests}
).execute()

Java

List<Request> requests = new ArrayList<>();
requests.add(new Request().setDeleteDropdownDefinition(
    new DeleteDropdownDefinitionRequest()
        .setDropdownDefinitionId("kix.review_status")
        .setTabId("t.0")));

BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest().setRequests(requests);
BatchUpdateDocumentResponse response = docsService.documents()
    .batchUpdate(DOCUMENT_ID, body)
    .execute();

Gestion des erreurs et dépannage

Conditions d'erreur courantes et solutions :

Code d'état Cause Solution
400 INVALID_ARGUMENT Format de préfixe d'ID ou d'expression régulière non valide. Assurez-vous que dropdownDefinitionId commence par kix. (6 à 18 caractères) et que optionId commence par dropdownItem. (15 à 27 caractères).
400 INVALID_ARGUMENT Le nombre d'options n'est pas autorisé. Une définition de menu déroulant doit contenir entre 2 et 50 options.
400 INVALID_ARGUMENT Le titre ou la valeur d'affichage sont vides ou dépassent 200 caractères. Fournissez une chaîne non vide comprenant entre 1 et 200 caractères.
400 INVALID_ARGUMENT Propriété de style de texte non compatible dans l'option. Seules les options foregroundColor et backgroundColor sont acceptées dans les menus déroulants. Supprimez la police, la taille ou d'autres attributs.
400 INVALID_ARGUMENT Mappage de remplacement d'option manquant lors de la suppression. Lorsque vous supprimez une option sélectionnée par un chip, indiquez une option de remplacement valide dans selectedOptionIdReplacements.
400 INVALID_ARGUMENT Tentative de suppression d'une définition en cours d'utilisation. Supprimez ou redéfinissez la cible de toutes les instances de chips de liste déroulante faisant référence à la définition avant de la supprimer.
400 INVALID_ARGUMENT ID fourni par l'utilisateur en double. Assurez-vous que les ID fournis par les utilisateurs sont uniques dans l'onglet "Document".