ทำงานกับชิปเมนูแบบเลื่อนลง

Google Docs API ช่วยให้คุณสร้าง แทรก อัปเดต อ่าน และจัดการชิปเมนูแบบเลื่อนลงภายในเอกสาร Google เอกสารได้โดยใช้โปรแกรม

ชิปเมนูแบบเลื่อนลงคืออะไร

ชิปเมนูแบบเลื่อนลงใน Google เอกสารช่วยให้ผู้ใช้มีเมนูการเลือกแบบโต้ตอบและปรับแต่งได้ในข้อความของเอกสาร ผู้ใช้สามารถคลิกชิปเมนูแบบเลื่อนลงเพื่อเลือกจากรายการตัวเลือกที่กำหนดไว้ล่วงหน้า ซึ่งแต่ละตัวเลือกจะมีข้อความที่แสดงและรูปแบบสีของตัวเอง ชิปเมนูแบบเลื่อนลงมักใช้สำหรับการติดตามโปรเจ็กต์ การอัปเดตสถานะ เวิร์กโฟลว์การตรวจสอบ และขั้นตอนการอนุมัติ

คุณทำสิ่งต่อไปนี้ได้ผ่าน Docs API

  • กำหนดเทมเพลตเมนูแบบเลื่อนลงที่นำมาใช้ซ้ำได้ด้วยชื่อ ตัวเลือก และสีที่กำหนดเอง
  • แทรกชิปเมนูแบบเลื่อนลงในตำแหน่งอักขระที่ถูกต้อง
  • อัปเดตตัวเลือกที่เลือกของอินสแตนซ์ชิปเมนูแบบเลื่อนลงแต่ละรายการ
  • แก้ไขคำจำกัดความของเมนูแบบเลื่อนลงที่แชร์ในที่เดียว ซึ่งจะอัปเดตชิปที่อ้างอิงทั้งหมดพร้อมกัน
  • แทนที่หรือเลิกใช้ตัวเลือกอย่างปลอดภัยในขณะที่ยังคงความสมบูรณ์ของการอ้างอิงในชิปที่มีอยู่
  • ลบเทมเพลตเมนูแบบเลื่อนลงที่ไม่ได้ใช้

สถาปัตยกรรม: คำจำกัดความและอินสแตนซ์

ใน Docs API ชิปเมนูแบบเลื่อนลงจะมีคำจำกัดความและอินสแตนซ์ คำจำกัดความจะตั้งค่าตัวเลือกสำหรับอินสแตนซ์เมนูแบบเลื่อนลง อินสแตนซ์ของเมนูแบบเลื่อนลงคือเมนูแบบเลื่อนลงที่ผู้ใช้โต้ตอบได้ และจะบันทึกข้อมูลเกี่ยวกับการเลือก

Docs API จะแยกการกำหนดค่าเทมเพลตเมนูแบบเลื่อนลงออกจากอินสแตนซ์ชิปเมนูแบบเลื่อนลงในบรรทัด ดังนี้

  1. DropdownDefinition: เทมเพลตระดับแท็บที่กำหนดชื่อเมนูแบบเลื่อนลงและชุดตัวเลือกที่เลือกได้ (DropdownOption) โดยไม่ได้อยู่ในออฟเซ็ตอักขระที่เฉพาะเจาะจงในเอกสาร แต่จะจัดเก็บไว้ในแผนที่คำจำกัดความของแท็บ: document.tabs[].documentTab.dropdownDefinitions
  2. เมนูแบบเลื่อนลง: อินสแตนซ์ชิปแต่ละรายการที่ฝังแบบอินไลน์ภายในองค์ประกอบย่อหน้า (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 ตัวพิมพ์เล็ก ซึ่งตรงกับรูปแบบที่สร้างโดย UI ของ Google เอกสาร

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 ครั้งเดียว

ตัวอย่างโค้ดต่อไปนี้จะสร้างคำจำกัดความของเมนูแบบเลื่อนลง "สถานะการตรวจสอบ" ที่มีตัวเลือก 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()

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 คำนำหน้า 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 รหัสที่ได้จากผู้ใช้ซ้ำกัน ตรวจสอบว่ารหัสที่ได้จากผู้ใช้ไม่ซ้ำกันในแท็บเอกสาร