ตรวจสอบตัวแปรอินพุต

คู่มือนี้อธิบายวิธียืนยันตัวแปรอินพุต

เมื่อกําหนดตัวแปรอินพุต แนวทางปฏิบัติแนะนําคือตรวจสอบว่าผู้ใช้ ป้อนค่าที่เหมาะสม เช่น หากคุณขอให้ผู้ใช้ป้อนตัวเลข การยืนยันว่าผู้ใช้ป้อน 1 แทน a จะเป็นการยืนยันว่าขั้นตอนของคุณทำงานโดยไม่มีข้อผิดพลาด

การตรวจสอบตัวแปรอินพุตทำได้ 2 วิธีดังนี้

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

การตรวจสอบฝั่งไคลเอ็นต์

การติดตั้งใช้งานการตรวจสอบฝั่งไคลเอ็นต์ทำได้ 2 วิธีดังนี้

  • สำหรับการตรวจสอบพื้นฐาน เช่น การยืนยันว่าวิดเจ็ตมีอักขระน้อยกว่าจำนวนหนึ่งๆ หรือมีสัญลักษณ์ @ ให้เรียกใช้คลาส Validation ของบริการการ์ดของส่วนเสริม Google Workspace
  • หากต้องการการตรวจสอบที่เชื่อถือได้ เช่น การเปรียบเทียบค่าของวิดเจ็ตกับค่าของวิดเจ็ตอื่นๆ คุณสามารถเพิ่มการตรวจสอบ Common Expression Language (CEL) ลงในวิดเจ็ตการ์ดที่รองรับต่อไปนี้ได้โดยใช้ CardService

เรียกใช้คลาส Validation

ตัวอย่างต่อไปนี้จะตรวจสอบว่าวิดเจ็ต TextInput มีอักขระไม่เกิน 10 ตัว

Apps Script

const validation = CardService.newValidation().setCharacterLimit('10').setInputType(
    CardService.InputType.TEXT);

หากต้องการตัวเลือกการตรวจสอบเพิ่มเติม ให้ใช้การตรวจสอบ CEL

การตรวจสอบ CEL

การตรวจสอบภาษาของนิพจน์ทั่วไป (CEL) จะตรวจสอบอินพุตได้ทันที โดยไม่มีเวลาในการตอบสนองของการตรวจสอบฝั่งเซิร์ฟเวอร์ด้วยการส่งต่อการตรวจสอบค่าอินพุตที่ไม่ขึ้นอยู่กับการค้นหาข้อมูลจากบริการอื่นๆ ไปยังฝั่งไคลเอ็นต์

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

การสร้างการตรวจสอบ CEL ที่สมบูรณ์เกี่ยวข้องกับคอมโพเนนต์ต่อไปนี้

  • ExpressionData ในการ์ด: มีตรรกะการตรวจสอบที่ระบุและตรรกะการทริกเกอร์วิดเจ็ต เมื่อเป็นไปตามเงื่อนไขที่กำหนดข้อใดข้อหนึ่ง

    • Id: ตัวระบุที่ไม่ซ้ำกันสำหรับ ExpressionData ภายใน การ์ดปัจจุบัน
    • Expression: สตริง CEL ที่กำหนดตรรกะการตรวจสอบ (เช่น "value1 == value2")
    • Conditions: รายการเงื่อนไขที่มีการเลือกผลการตรวจสอบที่กำหนดไว้ล่วงหน้า (SUCCESS หรือ FAILURE) เงื่อนไขจะเชื่อมโยง กับฝั่งวิดเจ็ต EventAction ผ่าน Triggers ด้วย actionRuleId ที่แชร์
    • ระดับการ์ด EventAction: เปิดใช้งานการตรวจสอบ CEL ในการ์ดและ เชื่อมโยงฟิลด์ ExpressionData กับวิดเจ็ตผลลัพธ์ผ่าน ทริกเกอร์หลังเหตุการณ์
      • actionRuleId: รหัสที่ไม่ซ้ำสำหรับ EventAction นี้
      • ExpressionDataAction: ตั้งค่าเป็น START_EXPRESSION_EVALUATION เพื่อ ระบุว่าการดำเนินการนี้เริ่มการประเมิน CEL
      • Trigger: เชื่อมต่อ Conditions กับ EventActions ฝั่งวิดเจ็ต โดยอิงตาม actionRuleId
  • EventAction ระดับวิดเจ็ต: ควบคุมลักษณะการทำงานของวิดเจ็ตผลลัพธ์เมื่อเป็นไปตามเงื่อนไข สำเร็จหรือล้มเหลว เช่น วิดเจ็ตผลลัพธ์อาจเป็น TextParagraph ที่มีข้อความแสดงข้อผิดพลาดซึ่งจะปรากฏ เมื่อการตรวจสอบไม่สำเร็จเท่านั้น

    • actionRuleId: ตรงกับ actionRuleId ใน Trigger ด้านบัตร
    • CommonWidgetAction: กำหนดการดำเนินการที่ไม่เกี่ยวข้องกับการประเมิน เช่น การอัปเดตระดับการมองเห็นของวิดเจ็ต
      • UpdateVisibilityAction: การดำเนินการที่อัปเดตสถานะระดับการเข้าถึงของวิดเจ็ต (VISIBLE หรือ HIDDEN)

ตัวอย่างต่อไปนี้แสดงวิธีใช้การตรวจสอบ CEL เพื่อดูว่าอินพุตข้อความ 2 รายการเท่ากันหรือไม่ ระบบจะแสดงข้อความแสดงข้อผิดพลาดหากค่าไม่เท่ากัน

  • เมื่อตรงตาม failCondition (อินพุตไม่เท่ากัน) ระบบจะตั้งค่าเครื่องมือข้อความแสดงข้อผิดพลาดเป็น VISIBLE และแสดงขึ้น
    รูปที่ 1: เมื่อตรงตามfailCondition (อินพุตไม่เท่ากัน) ระบบจะตั้งค่า วิดเจ็ตข้อความแสดงข้อผิดพลาดเป็น VISIBLE และวิดเจ็ตจะปรากฏขึ้น
  • เมื่อตรงตาม successCondition (อินพุตเท่ากัน) ระบบจะตั้งค่าเครื่องมือข้อความแสดงข้อผิดพลาดเป็น HIDDEN และจะไม่ปรากฏ
    รูปที่ 2: เมื่อเป็นไปตามsuccessCondition (อินพุตเท่ากัน) ระบบจะตั้งค่าวิดเจ็ตข้อความแสดงข้อผิดพลาด เป็น HIDDEN และจะไม่ปรากฏ

ตัวอย่างโค้ดแอปพลิเคชันและไฟล์ Manifest JSON มีดังนี้

Apps Script

function onConfig() {

  // Create a Card
  let card = CardService.newCardBuilder();

  const textInput_1 = CardService.newTextInput()
    .setTitle("Input number 1")
    .setFieldName("value1"); // FieldName's value must match a corresponding ID defined in the inputs[] array in the manifest file.
  const textInput_2 = CardService.newTextInput()
    .setTitle("Input number 2")
    .setFieldName("value2"); // FieldName's value must match a corresponding ID defined in the inputs[] array in the manifest file.
  let sections = CardService.newCardSection()
    .setHeader("Two number equals")
    .addWidget(textInput_1)
    .addWidget(textInput_2);

  // CEL Validation

  // Define Conditions
  const condition_success = CardService.newCondition()
    .setActionRuleId("CEL_TEXTINPUT_SUCCESS_RULE_ID")
    .setExpressionDataCondition(
      CardService.newExpressionDataCondition()
      .setConditionType(
        CardService.ExpressionDataConditionType.EXPRESSION_EVALUATION_SUCCESS));
  const condition_fail = CardService.newCondition()
    .setActionRuleId("CEL_TEXTINPUT_FAILURE_RULE_ID")
    .setExpressionDataCondition(
      CardService.newExpressionDataCondition()
      .setConditionType(
        CardService.ExpressionDataConditionType.EXPRESSION_EVALUATION_FAILURE));

  // Define Card-side EventAction
  const expressionDataAction = CardService.newExpressionDataAction()
    .setActionType(
      CardService.ExpressionDataActionType.START_EXPRESSION_EVALUATION);
  // Define Triggers for each Condition respectively
  const trigger_success = CardService.newTrigger()
    .setActionRuleId("CEL_TEXTINPUT_SUCCESS_RULE_ID");
  const trigger_failure = CardService.newTrigger()
    .setActionRuleId("CEL_TEXTINPUT_FAILURE_RULE_ID");

  const eventAction = CardService.newEventAction()
    .setActionRuleId("CEL_TEXTINPUT_EVALUATION_RULE_ID")
    .setExpressionDataAction(expressionDataAction)
    .addPostEventTrigger(trigger_success)
    .addPostEventTrigger(trigger_failure);

  // Define ExpressionData for the current Card
  const expressionData = CardService.newExpressionData()
    .setId("expData_id")
    .setExpression("value1 == value2") // CEL expression
    .addCondition(condition_success)
    .addCondition(condition_fail)
    .addEventAction(eventAction);
  card = card.addExpressionData(expressionData);

  // Create Widget-side EventActions and a widget to display error message
  const widgetEventActionFail = CardService.newEventAction()
    .setActionRuleId("CEL_TEXTINPUT_FAILURE_RULE_ID")
    .setCommonWidgetAction(
      CardService.newCommonWidgetAction()
      .setUpdateVisibilityAction(
        CardService.newUpdateVisibilityAction()
        .setVisibility(
          CardService.Visibility.VISIBLE)));
  const widgetEventActionSuccess = CardService.newEventAction()
    .setActionRuleId("CEL_TEXTINPUT_SUCCESS_RULE_ID")
    .setCommonWidgetAction(
      CardService.newCommonWidgetAction()
      .setUpdateVisibilityAction(
        CardService.newUpdateVisibilityAction()
        .setVisibility(
          CardService.Visibility.HIDDEN)));
  const errorWidget = CardService.newTextParagraph()
    .setText("The first and second value must match.")
    .setVisibility(CardService.Visibility.HIDDEN) // Initially hidden
    .addEventAction(widgetEventActionFail)
    .addEventAction(widgetEventActionSuccess);
  sections = sections.addWidget(errorWidget);

  card = card.addSection(sections);
  // Build and return the Card
  return card.build();
}

ไฟล์ Manifest JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "CEL validation example",
      "logoUrl": "https://www.gstatic.com/images/branding/productlogos/calculator_search/v1/web-24dp/logo_calculator_search_color_1x_web_24dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "actionElement",
          "state": "ACTIVE",
          "name": "CEL Demo",
          "description": "Demonstrates CEL Validation",
          "workflowAction": {
            "inputs": [
              {
                "id": "value1",
                "description": "The first number",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "INTEGER"
                }
              },
              {
                "id": "value2",
                "description": "The second number",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "INTEGER"
                }
              }
            ],
            "onConfigFunction": "onConfig",
            "onExecuteFunction": "onExecute"
          }
        }
      ]
    }
  }
}

วิดเจ็ตและการดำเนินการตรวจสอบ CEL ที่รองรับ

วิดเจ็ตบัตรที่รองรับการตรวจสอบ CEL

วิดเจ็ตต่อไปนี้รองรับการตรวจสอบ CEL

  • TextInput
  • SelectionInput
  • DateTimePicker

การดำเนินการตรวจสอบ CEL ที่รองรับ

  • การดำเนินการทางคณิตศาสตร์
    • +: เพิ่มตัวเลข 2 ตัว int64, uint64 หรือ double
    • -: ลบตัวเลข 2 ตัว int64, uint64 หรือ double
    • *: คูณตัวเลข int64, uint64 หรือ double 2 ตัว
    • /: หารตัวเลข int64, uint64 หรือ double 2 ตัว (การหารจำนวนเต็ม)
    • %: คำนวณมอดุโลของตัวเลข int64 หรือ uint64 2 ตัว
    • -: ปฏิเสธตัวเลข int64 หรือ uint64
  • การดำเนินการเชิงตรรกะ
    • &&: ดำเนินการ AND เชิงตรรกะกับค่าบูลีน 2 ค่า
    • ||: ดำเนินการ OR เชิงตรรกะกับค่าบูลีน 2 ค่า
    • !: ดำเนินการ NOT เชิงตรรกะกับค่าบูลีน
  • การดำเนินการเปรียบเทียบ
    • ==: ตรวจสอบว่าค่า 2 ค่าเท่ากันหรือไม่ รองรับตัวเลขและรายการ
    • !=: ตรวจสอบว่าค่า 2 ค่าไม่เท่ากันหรือไม่ รองรับตัวเลขและรายการ
    • <: ตรวจสอบว่าตัวเลขแรก int64, uint64 หรือ double น้อยกว่าตัวเลขที่ 2 หรือไม่
    • <=: ตรวจสอบว่าตัวเลขแรก int64, uint64 หรือ double น้อยกว่าหรือเท่ากับตัวเลขที่สองหรือไม่
    • >: ตรวจสอบว่าตัวเลขแรก int64, uint64 หรือ double มากกว่าตัวเลขที่ 2 หรือไม่
    • >=: ตรวจสอบว่าตัวเลขแรก int64, uint64 หรือ double มากกว่าหรือเท่ากับตัวเลขที่ 2 หรือไม่
  • การดำเนินการกับรายการ:
    • in: ตรวจสอบว่ามีค่าอยู่ในรายการหรือไม่ รองรับตัวเลข สตริง และลิสต์ที่ซ้อนกัน
    • size: แสดงผลจำนวนรายการในรายการ รองรับตัวเลขและรายการที่ซ้อนกัน

สถานการณ์การตรวจสอบ CEL ที่ไม่รองรับ

  • ขนาดอาร์กิวเมนต์ไม่ถูกต้องสำหรับการดำเนินการไบนารี: การดำเนินการไบนารี (เช่น add_int64, เท่ากับ) ต้องมีอาร์กิวเมนต์ 2 รายการเท่านั้น การระบุจำนวนอาร์กิวเมนต์ที่แตกต่างกันจะทำให้เกิดข้อผิดพลาด
  • ขนาดอาร์กิวเมนต์ไม่ถูกต้องสำหรับการดำเนินการแบบเอกภาค: การดำเนินการแบบเอกภาค (เช่น negate_int64) ต้องมีอาร์กิวเมนต์ 1 รายการเท่านั้น การระบุจำนวนอาร์กิวเมนต์ที่แตกต่างกันจะทำให้เกิดข้อผิดพลาด
  • ประเภทที่ไม่รองรับในการดำเนินการเชิงตัวเลข: การดำเนินการแบบไบนารีและแบบเอกภาคเชิงตัวเลขยอมรับเฉพาะอาร์กิวเมนต์ที่เป็นตัวเลข การระบุประเภทอื่นๆ (เช่น บูลีน) จะทำให้เกิดข้อผิดพลาด

การตรวจสอบฝั่งเซิร์ฟเวอร์

การตรวจสอบฝั่งเซิร์ฟเวอร์ช่วยให้คุณเรียกใช้ตรรกะฝั่งเซิร์ฟเวอร์ได้โดยการระบุ onSaveFunction() ในโค้ดของขั้นตอน เมื่อผู้ใช้ออกจาก การ์ดการกำหนดค่าของขั้นตอน onSaveFunction() จะทํางานและให้คุณยืนยันอินพุตของผู้ใช้ได้

หากข้อมูลที่ผู้ใช้ป้อนถูกต้อง ให้แสดงผล saveWorkflowAction

หากข้อมูลที่ผู้ใช้ป้อนไม่ถูกต้อง ให้แสดงการ์ดการกำหนดค่าซึ่งแสดงข้อความแสดงข้อผิดพลาดแก่ผู้ใช้ที่อธิบายวิธีแก้ไขข้อผิดพลาด

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

id ของอินพุตที่ตรวจสอบแล้วแต่ละรายการในไฟล์ Manifest ต้องตรงกับ name ของวิดเจ็ตการ์ดในโค้ด

ตัวอย่างต่อไปนี้จะตรวจสอบว่าข้อความที่ผู้ใช้ป้อนมีเครื่องหมาย "@" หรือไม่

ไฟล์ Manifest

ข้อมูลที่ตัดตอนมาจากไฟล์ Manifest ระบุonSaveFunction()ชื่อ "onSave" ดังนี้

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Server-side validation example",
      "logoUrl": "https://www.gstatic.com/images/branding/productlogos/calculator_search/v1/web-24dp/logo_calculator_search_color_1x_web_24dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "actionElement",
          "state": "ACTIVE",
          "name": "Calculate",
          "description": "Asks the user for an email address",
          "workflowAction": {
            "inputs": [
              {
                "id": "email",
                "description": "email address",
                "cardinality": "SINGLE",
                "required": true,
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "onConfigFunction": "onConfigCalculate",
            "onExecuteFunction": "onExecuteCalculate",
            "onSaveFunction": "onSave"
          }
        }
      ]
    }
  }
}

โค้ดของแอปพลิเคชัน

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

Apps Script

/**
 * Validates user input asynchronously when the user
 * navigates away from a step's configuration card.
*/
function onSave(event) {

  // "email" matches the input ID specified in the manifest file.
  var email = event.workflow.actionInvocation.inputs["email"];

  // Validate that the email address contains an "@" sign:
  if(email.includes("@")) {

  // If successfully validated, save and proceed.
    return {
      "hostAppAction" : {
        "workflowAction" : {
          "saveWorkflowAction" : {}
        }
      }
    };

  // If the input is invalid, return a card with an error message
  } else {

var card = {
    "sections": [
      {
        "header": "Collect Email",
        "widgets": [
          {
            "textInput": {
              "name": "email",
              "label": "email address",
              "hostAppDataSource" : {
                "workflowDataSource" : {
                  "includeVariables" : true
                }
              }
            }
          },
          {
            "textParagraph": {
              "text": "<b>Error:</b> Email addresses must include the '@' sign.",
              "maxLines": 1
            }
          }
        ]
      }
    ]
  };
  return pushCard(card);
  }
}