Google Docs API를 사용하면 Google Docs 문서 내에서 드롭다운 칩을 프로그래매틱 방식으로 만들고, 삽입하고, 업데이트하고, 읽고, 관리할 수 있습니다.
드롭다운 칩이란 무엇인가요?
Google Docs의 드롭다운 칩은 문서 텍스트 내에 대화형의 맞춤설정 가능한 선택 메뉴를 제공합니다. 사용자는 드롭다운 칩을 클릭하여 사전 정의된 옵션 목록에서 선택할 수 있으며 각 옵션에는 자체 표시 텍스트와 색상 스타일이 있습니다. 드롭다운 칩은 프로젝트 추적, 상태 업데이트, 검토 워크플로, 승인 단계에 자주 사용됩니다.
Docs API를 사용하면 다음 작업을 할 수 있습니다.
- 맞춤 제목, 옵션 이름, 색상으로 재사용 가능한 드롭다운 템플릿을 정의합니다.
- 유효한 문자 위치에 드롭다운 칩을 삽입합니다.
- 개별 드롭다운 칩 인스턴스의 선택된 옵션을 업데이트합니다.
- 참조하는 모든 칩을 동시에 업데이트하여 공유 드롭다운 정의를 수정합니다.
- 기존 칩 전반에서 참조 무결성을 유지하면서 옵션을 안전하게 대체하거나 사용 중지합니다.
- 사용하지 않는 드롭다운 템플릿을 삭제합니다.
아키텍처: 정의 및 인스턴스
Docs API에서 드롭다운 칩에는 정의와 인스턴스가 있습니다. 정의는 드롭다운 인스턴스의 옵션을 설정합니다. 드롭다운 인스턴스는 사용자가 상호작용할 수 있는 드롭다운이며 선택에 관한 정보를 저장합니다.
Docs API는 드롭다운 템플릿 구성을 인라인 드롭다운 칩 인스턴스와 분리합니다.
- DropdownDefinition: 드롭다운 제목과 선택 가능한 선택사항(
DropdownOption)의 모음을 정의하는 탭 수준 템플릿입니다. 문서의 특정 문자 오프셋에 상주하지 않고 탭의 정의 맵(document.tabs[].documentTab.dropdownDefinitions)에 저장됩니다. - 드롭다운: 단락 요소 (
ParagraphElement.dropdown) 내에 인라인으로 삽입된 개별 칩 인스턴스입니다. 각 드롭다운 인스턴스는dropdownDefinitionId를 참조하고 자체 활성selectedOptionId를 저장합니다.
DropdownDefinition를 수정하면 (예: 옵션 추가 또는 제목 이름 바꾸기) 각 요소를 업데이트하지 않아도 탭 전체에서 참조하는 모든 칩이 업데이트됩니다.
각 Dropdown 인스턴스는 자체 selectedOptionId를 추적합니다. 개별 칩의 선택된 값을 변경하면 해당 인스턴스에만 영향을 미칩니다.
ID 형식 및 유효성 검사 규칙
사용자 제공 ID는 엄격한 형식, 접두사, 길이 사양을 준수해야 합니다.
| 식별자 | 필수 접두사 | 검사 정규 표현식 | 길이 제한 | 예 |
|---|---|---|---|---|
드롭다운 정의 ID (dropdownDefinitionId) |
kix. |
^kix\.[a-zA-Z0-9_-]{2,14}$ |
6~18자(영문 기준) | kix.review_status |
드롭다운 옵션 ID (optionId) |
dropdownItem. |
^dropdownItem\.[a-zA-Z0-9_-]{2,14}$ |
15~27자(영문 기준) | dropdownItem.pending |
사용자 제공 ID 생성
필수 접두사 및 정규 표현식 요구사항을 준수하는 ID를 생성하려면 다음 도우미 함수를 사용하세요. 이러한 도우미는 Google Docs UI에서 생성된 형식과 일치하는 소문자 base-36 영숫자 접미사를 생성합니다.
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}"
자바
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();
}
}
드롭다운 칩 만들기 및 삽입하기
단일 배치 생성 (권장)
가장 효율적인 패턴은 하나의 documents.batchUpdate 호출에서 CreateDropdownDefinitionRequest와 InsertDropdownRequest를 결합합니다.
다음 코드 샘플은 사용자가 제공한 ID를 사용하여 색상 코딩된 선택사항이 3개인 '검토 상태' 드롭다운 정의를 만들고 문서 끝에 인스턴스를 삽입합니다.
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()
자바
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자를 초과할 수 없습니다. - 옵션 스타일 지정:
DropdownOption.textStyle에서는foregroundColor및backgroundColor만 지원됩니다. 다른 스타일 속성을 설정하면400 Bad Request오류가 반환됩니다. - 기본 선택:
InsertDropdownRequest에서selectedOptionId가 생략되면 칩은DropdownDefinition에 정의된 첫 번째 옵션으로 기본 설정됩니다.
개별 드롭다운 칩 선택 업데이트
템플릿이나 다른 칩을 변경하지 않고 기존 드롭다운 칩 인스턴스의 선택된 옵션을 변경하려면 UpdateDropdownPropertiesRequest을 사용하세요.
dropdownId: (필수) 업데이트할 특정 드롭다운 칩 인스턴스의 ID입니다.tabId: 드롭다운이 포함된 탭의 ID입니다 (생략된 경우 첫 번째 탭이 기본값임).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()
자바
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이 있는 옵션)을 포함하면 정의에 추가됩니다. - 업데이트된 옵션: 수정된
displayValue또는textStyle업데이트가 포함된 기존optionId를 제공하면 해당 옵션이 제자리에서 업데이트됩니다. - 옵션 순서 변경: 옵션 목록이 요청에 제공된 정확한 순서로 저장됩니다.
- 삭제된 옵션: 기존
optionId를 생략하면 정의에서 해당 옵션이 삭제됩니다.
참조 무결성 및 옵션 대체
삭제되는 옵션이 문서 내의 드롭다운 칩에서 선택된 경우 selectedOptionIdReplacements (map<string, string>)에 매핑을 제공해야 합니다. 키는 삭제되는 옵션의 ID이고 값은 대체 옵션의 ID입니다.
다음 코드 샘플은 옵션 대체로 드롭다운 정의를 업데이트하는 방법을 보여줍니다.
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()
자바
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()
자바
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 |
잘못된 ID 접두사 또는 정규 표현식 형식입니다. | 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 |
사용자가 제공한 ID가 중복됩니다. | 사용자 제공 ID가 문서 탭 내에서 고유해야 합니다. |
관련 주제
- 탭 작업
- 텍스트 서식 지정하기
- 댓글 및 제안 사용하기
- REST 리소스: documents.request
- REST 리소스: documents
- REST 리소스: documents.batchUpdate