איך עובדים עם צ'יפים שנפתחים לרשימה

‫Google Docs API מאפשר לכם ליצור, להוסיף, לעדכן, לקרוא ולנהל צ'יפים שנפתחים לרשימה במסמכים ב-Google Docs באופן פרוגרמטי.

מהם צ'יפים שנפתחים לרשימה?

צ'יפים שנפתחים לרשימה ב-Google Docs מספקים למשתמשים תפריט בחירה אינטראקטיבי שניתן להתאמה אישית, בתוך הטקסט של המסמך. המשתמשים יכולים ללחוץ על צ'יפ שנפתח לרשימה כדי לבחור מתוך רשימה מוגדרת מראש של אפשרויות, שלכל אחת מהן יש טקסט תצוגה וסגנון צבע משלה. צ'יפים שנפתחים לרשימה משמשים לעיתים קרובות למעקב אחרי פרויקטים, לעדכוני סטטוס, לתהליכי עבודה של בדיקות ולשלבי אישור.

באמצעות Docs API, אפשר:

  • הגדרת תבניות של תפריטים נפתחים לשימוש חוזר עם כותרות, שמות של אפשרויות וצבעים בהתאמה אישית.
  • מוסיפים צ'יפים של תפריט נפתח במיקום תקין של תו.
  • עדכון האפשרות שנבחרה במופע ספציפי של צ'יפ תפריט נפתח.
  • לשנות הגדרות של תפריטים נפתחים משותפים במקום, ולעדכן את כל הצ'יפים שמפנים אליהם בו-זמנית.
  • החלפה או הוצאה משימוש של אפשרויות בצורה בטוחה, תוך שמירה על שלמות ההפניה בכל הצ'יפים הקיימים.
  • מחיקת תבניות של תפריטים נפתחים שלא בשימוש.

ארכיטקטורה: הגדרות ומופעים

ב-Docs API, לצ'יפים שנפתחים לרשימה יש הגדרות ומופעים. הגדרה קובעת אפשרויות למופע של תפריט נפתח. מופע של תפריט נפתח הוא תפריט נפתח שאנשים יכולים לבצע בו אינטראקציה, והוא שומר מידע על הבחירות שלהם.

‫Docs API מפריד בין הגדרת תבנית התפריט הנפתח לבין מופעים של צ'יפים שנפתחים לרשימה בתוך השורה:

  1. ‫DropdownDefinition: תבנית ברמת הכרטיסייה שמגדירה את הכותרת של התפריט הנפתח ואת אוסף האפשרויות לבחירה (DropdownOption). היא לא נמצאת בהיסט מסוים של תווים במסמך, אלא מאוחסנת במפת ההגדרות של הכרטיסייה: document.tabs[].documentTab.dropdownDefinitions.
  2. ‫Dropdown: מופע צ'יפ בודד שמוטמע בתוך פסקה (ParagraphElement.dropdown). כל מופע של רשימה נפתחת מפנה אל dropdownDefinitionId ומאחסן את selectedOptionId הפעיל שלו.

שינוי של DropdownDefinition (למשל, הוספת אפשרות או שינוי השם) מעדכן את כל הצ'יפים שמפנים אליו בכרטיסייה, בלי שצריך לעדכן כל רכיב בנפרד.

כל מופע של Dropdown עוקב אחרי selectedOptionId משלו. שינוי הערך שנבחר של צ'יפ ספציפי משפיע רק על המופע הספציפי הזה.

כללים לאימות ולפורמט של מזהים

מזהים שהמשתמשים סיפקו חייבים לעמוד במפרטים מחמירים של פורמט, קידומת ואורך:

מזהה תחילית חובה ביטוי רגולרי לאימות מגבלת אורך דוגמה
מזהה הגדרת התפריט הנפתח (dropdownDefinitionId) kix. ^kix\.[a-zA-Z0-9_-]{2,14}$ ‫6 עד 18 תווים kix.review_status
מזהה אפשרות בתפריט הנפתח (optionId) dropdownItem. ^dropdownItem\.[a-zA-Z0-9_-]{2,14}$ ‫15 עד 27 תווים dropdownItem.pending

יצירת מזהים שהמשתמשים סיפקו

כדי ליצור מזהים שעומדים בדרישות של קידומת חובה וביטוי רגולרי, אפשר להשתמש בפונקציות העזר הבאות. העוזרים האלה יוצרים סיומות אלפאנומריות בבסיס 36 באותיות קטנות, שתואמות לפורמט שנוצר על ידי ממשק המשתמש של 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();
  }
}

איך יוצרים ומוסיפים צ'יפים שנפתחים לרשימה

יצירה של קבוצה אחת (מומלץ)

הדפוס הכי יעיל הוא שילוב של CreateDropdownDefinitionRequest ושל InsertDropdownRequest בשיחה אחת של documents.batchUpdate.

דוגמת הקוד הבאה יוצרת הגדרה של תפריט נפתח 'סטטוס הבדיקה' עם שלוש אפשרויות שמקודדות בצבעים באמצעות מזהים שסופקו על ידי המשתמש, ומוסיפה מופע בסוף המסמך:

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();

כללים ומגבלות לאימות נתונים בתפריטים נפתחים

כשיוצרים או משנים הגדרות של תפריטים נפתחים, חלות ההגבלות הבאות:

  • מספר האפשרויות: בהגדרת תפריט נפתח צריך להיות בין 2 ל-50 אפשרויות.
  • אורך הכותרת: ההגדרה title לא יכולה להיות ריקה, והיא לא יכולה לכלול יותר מ-200 תווים.
  • אורך ערך התצוגה: הערך displayValue של כל אפשרות לא יכול להיות ריק, והוא לא יכול לחרוג מ-200 תווים.
  • סגנון האפשרות: רק הערכים foregroundColor ו-backgroundColor נתמכים ב-DropdownOption.textStyle. הגדרת מאפייני סגנון אחרים מחזירה שגיאת 400 Bad Request.
  • בחירת ברירת מחדל: ב-InsertDropdownRequest, אם לא מציינים את selectedOptionId, ברירת המחדל של הצ'יפ היא האפשרות הראשונה שמוגדרת ב-DropdownDefinition.

עדכון של בחירה בצ'יפ שנפתח לרשימה

כדי לשנות את האפשרות שנבחרה במופע קיים של צ'יפ שנפתח לרשימה בלי לשנות את התבנית או צ'יפים אחרים, משתמשים ב-UpdateDropdownPropertiesRequest:

  • ‫dropdownId: (חובה) המזהה של מופע הצ'יפ שנפתח לרשימה הספציפי שרוצים לעדכן.
  • ‫tabId: המזהה של הכרטיסייה שמכילה את התפריט הנפתח (ברירת המחדל היא הכרטיסייה הראשונה אם לא מציינים אחרת).
  • ‫fields: מוגדר ל-"selectedOptionId".

בדוגמת הקוד הבאה, אנחנו מעדכנים את הבחירה הפעילה בצ'יפ שנפתח לרשימה ל-"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();

עדכון ההגדרות והאפשרויות של תפריטים נפתחים

כדי לשנות את התבנית עצמה (הכותרת, רשימת האפשרויות, תוויות התצוגה או הצבעים), משתמשים בסמל UpdateDropdownDefinitionPropertiesRequest. עדכון של הגדרה מוביל לעדכון אוטומטי של כל הצ'יפים שנפתחים לרשימה שמפנים אליה בכרטיסייה.

החלפה של רשימת האפשרויות המלאה

אם dropdownDefinitionProperties.options נכלל במסכת fields, הבקשה מבצעת החלפה מלאה של הרשימה. צריך לספק את הרשימה המלאה של האפשרויות בסדר שנבחר. השרת משווה את הרשימה הנכנסת להגדרה הנוכחית:

  • אפשרות חדשה: הוספת אפשרות בלי optionId (או עם optionId חדש שסופק על ידי המשתמש) מוסיפה אותה להגדרה.
  • אפשרות מעודכנת: אם מספקים optionId קיים עם עדכונים לdisplayValue או לtextStyle, האפשרות הזו מתעדכנת במקום.
  • אפשרויות שסודרו מחדש: רשימת האפשרויות נשמרת בדיוק לפי הסדר שצוין בבקשה.
  • אפשרות שנמחקה: אם משמיטים את optionId, האפשרות הזו נמחקת מההגדרה.

שלמות רפרנציאלית והחלפת אפשרויות

אם אפשרות שנמחקת נבחרה בצ'יפ שנפתח לרשימה כלשהו במסמך, חובה לספק מיפוי ב-selectedOptionIdReplacements (map<string, string>). המפתחות הם המזהים של האפשרויות שנמחקות, והערכים הם המזהים של האפשרויות החלופיות.

בדוגמת הקוד הבאה אפשר לראות איך מעדכנים הגדרה של תפריט נפתח עם החלפות של אפשרויות:

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();

מחיקה של הגדרת תפריט נפתח

כדי להסיר תבנית של תפריט נפתח שלא נמצאת בשימוש, משתמשים ב-DeleteDropdownDefinitionRequest.

בדוגמת הקוד הבאה אפשר לראות איך למחוק הגדרה של תפריט נפתח:

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();

טיפול בשגיאות ופתרון בעיות

תנאי שגיאה נפוצים ופתרונות:

קוד סטטוס סיבה רזולוציה
400 INVALID_ARGUMENT הפורמט של הקידומת של המזהה או של הביטוי הרגולרי לא תקין. הערך של dropdownDefinitionId צריך להתחיל ב-kix. (6-18 תווים) והערך של optionId צריך להתחיל ב-dropdownItem. (15-27 תווים).
400 INVALID_ARGUMENT מספר האפשרויות מחוץ לתחום. הגדרה של תפריט נפתח חייבת להכיל בין 2 ל-50 אפשרויות.
400 INVALID_ARGUMENT הכותרת או ערך התצוגה ריקים או שהם ארוכים מ-200 תווים. צריך לציין מחרוזת לא ריקה באורך של 1 עד 200 תווים.
400 INVALID_ARGUMENT מאפיין סגנון טקסט לא נתמך באפשרות. רק האפשרויות foregroundColor ו-backgroundColor נתמכות בתפריט הנפתח. מסירים את הגופן, הגודל או מאפיינים אחרים.
400 INVALID_ARGUMENT חסר מיפוי להחלפת אפשרות במקרה של מחיקה. כשמוחקים אפשרות שנבחרה על ידי צ'יפ כלשהו, צריך לספק חלופה תקינה ב-selectedOptionIdReplacements.
400 INVALID_ARGUMENT הייתה ניסיון למחוק הגדרה שנמצאת בשימוש. לפני שמוחקים את ההגדרה, צריך למחוק את כל המופעים של צ'יפים שנפתחים לרשימה שמפנים להגדרה או להגדיר מחדש את הטירגוט שלהם.
400 INVALID_ARGUMENT מזהה כפול שסופק על ידי המשתמש. מוודאים שהמזהים שהמשתמשים סיפקו הם ייחודיים בכרטיסיית המסמך.