جمع البيانات باستخدام متغيّر إدخال

يوضّح هذا الدليل كيفية إنشاء متغيّر إدخال.

لتنفيذ الخطوات، يجب توفير معلومات معيّنة. على سبيل المثال، يتطلّب إرسال رسالة إلكترونية توفُّر عنوان بريد إلكتروني. لتوفير هذه المعلومات الضرورية للخطوات، حدِّد متغيّرات الإدخال. بعد تحديدها، يضبط المستخدم عادةً متغيرات الإدخال في بطاقة إعداد الخطوة أثناء إعدادها.

حدِّد متغيّر الإدخال في مكانَين: ملف البيان الخاص بالإضافة، وفي الرمز باستخدام بطاقة إعداد حيث يمكن للمستخدمين إدخال قيم لمتغيّرات الإدخال.

تحديد متغيّر الإدخال في ملف البيان

في ملف البيان، حدِّد متغيّرات الإدخال باستخدام مصفوفة inputs[]. يحتوي كل عنصر في مصفوفة inputs[] على السمات التالية:

  • id: معرّف فريد لمتغيّر إدخال. للسماح للتدفق بربط عنصر إدخال بطاقة الإعدادات بمتغيّر الإدخال هذا، يجب أن يتطابق مع اسم عنصر البطاقة المقابل.
  • description: وصف لمتغيّر الإدخال سيتم عرضه للمستخدمين النهائيين.
  • cardinality: عدد القيم المسموح بها القيم المحتمَلة هي:
    • SINGLE: يُسمح بقيمة واحدة فقط.
  • dataType: نوع القيم المقبولة تحتوي dataType على السمة basicType التي تحدّد نوع البيانات. تشمل القيم الصالحة ما يلي:
    • STRING: سلسلة أبجدية رقمية
    • INTEGER: رقم
    • TIMESTAMP: طابع زمني بتنسيق "بالملي ثانية منذ بدء حقبة Unix" على سبيل المثال، يتم تمثيل 27 نوفمبر 2025، الساعة 16:49:02 بالتوقيت العالمي المنسّق على النحو التالي: 1764262142988.
    • BOOLEAN: إما true أو false.
    • EMAIL_ADDRESS: عنوان بريد إلكتروني بالتنسيق dana@example.com

يحدّد المثال التالي ثلاثة متغيّرات إدخال لخطوة آلة حاسبة. المتغيران المدخلان الأولان هما أعداد صحيحة، والثالث هو عملية حسابية.

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Calculator",
      "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": "calculatorDemo",
          "state": "ACTIVE",
          "name": "Calculate",
          "description": "Asks the user for two values and a math operation, then performs the math operation on the values and outputs the result.",
          "workflowAction": {
            "inputs": [
              {
                "id": "value1",
                "description": "value1",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "INTEGER"
                }
              },
              {
                "id": "value2",
                "description": "value2",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "INTEGER"
                }
              },
              {
                "id": "operation",
                "description": "operation",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "outputs": [
              {
                "id": "result",
                "description": "Calculated result",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "INTEGER"
                }
              }
            ],
            "onConfigFunction": "onConfigCalculate",
            "onExecuteFunction": "onExecuteCalculate"
          }
        }
      ]
    }
  }
}

تحديد متغيّر الإدخال في الرمز

يتضمّن رمز الخطوة دالة باسم onConfigFunction() تعرض بطاقة إعدادات تحدّد عنصرًا واحدًا من عناصر واجهة المستخدم لبطاقة الإدخال لكل متغيّر إدخال محدّد في مصفوفة inputs[] بملف البيان.

تتضمّن التطبيقات المصغّرة للإدخال المحدّدة في بطاقة الإعداد المتطلبات التالية:

  • يجب أن تتطابق سمة name لكل أداة إدخال مع سمة id لمتغير الإدخال المقابل في ملف البيان.
  • يجب أن تتطابق عددية عنصر الإدخال مع cardinalityمتغير الإدخال في ملف البيان.
  • يجب أن يتطابق نوع بيانات أداة الإدخال مع dataType متغير الإدخال في ملف البيان. إذا كان متغيّر الإدخال يتضمّن dataType عدد صحيح، لا يمكنه الاحتفاظ بسلسلة.

للحصول على مساعدة في إنشاء واجهات البطاقات، اطّلِع على أحد الخيارات التالية:

يعرض المثال التالي بطاقة إعدادات لكل أداة إدخال محدّدة في تحديد متغير الإدخال في ملف البيان.

برمجة التطبيقات

/**
* Generates and displays a configuration card for the sample calculation step.
*
* This function creates a card with input fields for two values and a drop-down
* for selecting an arithmetic operation.
*
* The input fields are configured to let the user select outputs from previous
* workflow steps as input values using the `hostAppDataSource` property.
*/
function onConfigCalculate() {
  const firstInput = CardService.newTextInput()
    .setFieldName("value1") // "FieldName" must match an "id" in the manifest file's inputs[] array.
    .setTitle("First Value")
    .setHostAppDataSource(
      CardService.newHostAppDataSource()
        .setWorkflowDataSource(
          CardService.newWorkflowDataSource()
            .setIncludeVariables(true)
        )
    );

  const secondInput = CardService.newTextInput()
    .setFieldName("value2") // "FieldName" must match an "id" in the manifest file's inputs[] array.
    .setTitle("Second Value")
    .setHostAppDataSource(
      CardService.newHostAppDataSource()
        .setWorkflowDataSource(
          CardService.newWorkflowDataSource()
            .setIncludeVariables(true)
        )
    );

  const selectionInput = CardService.newSelectionInput()
    .setTitle("operation")
    .setFieldName("operation") // "FieldName" must match an "id" in the manifest file's inputs[] array.
    .setType(CardService.SelectionInputType.DROPDOWN)
    .addItem("+", "+", false)
    .addItem("-", "-", true)
    .addItem("x", "x", false)
    .addItem("/", "/", false);

  const sections = CardService.newCardSection()
    .setHeader("Action_sample: Calculate")
    .setId("section_1")
    .addWidget(firstInput)
    .addWidget(selectionInput)
    .addWidget(secondInput)

  let card = CardService.newCardBuilder()
    .addSection(sections)
    .build();

  return card;
}

استخدام متغيّرات الناتج من الخطوات السابقة

يمكنك ضبط متغيّرات الإدخال لقبول متغيّرات الإخراج من الخطوات السابقة في سير العمل.

تفعيل اختيار المتغيّرات

للسماح للمستخدمين باختيار متغيّرات من خطوات سابقة، استخدِم السمة includeVariables في أدوات TextInput وSelectionInput.

تتضمّن أدوات TextInput وSelectionInput الميزات التالية الخاصة بـ Workspace Studio:

  • includeVariables: سمة منطقية تتيح للمستخدمين اختيار متغيرات من الخطوات السابقة. لكي يظهر أداة اختيار المتغير في الخطوات اللاحقة، يجب ربط كل من الحدث الأوّلي ومتغير الناتج واحد على الأقل بالمتغير.
  • type: قيمة تعدادية تُكمل الاقتراحات تلقائيًا. تشمل القيم المسموح بها ما يلي:
    • USER: تقدّم اقتراحات للإكمال التلقائي لأسماء الأشخاص في جهات اتصال المستخدم.
    • SPACE: يقدّم اقتراحات إكمال تلقائي لمساحات Google Chat التي يكون المستخدم عضوًا فيها.

عند ضبط كل من includeVariables وtype، يجمع حقل الإدخال بين تجارب كل منهما. يمكن للمستخدمين اختيار متغيّر من type المطابق من قائمة منسدلة، والاطّلاع على اقتراحات الإكمال التلقائي الخاصة به.

  • اقتراحات الإكمال التلقائي لمساحة في Google Chat
    الشكل 4: يراجع المستخدم اقتراحات الإكمال التلقائي عند اختيار مساحة.
  • تتيح قائمة المتغيّرات للمستخدمين اختيار متغيّرات الإخراج من الخطوات السابقة.
    الشكل 5: يختار المستخدم متغيّر الإخراج لخطوة سابقة من القائمة المنسدلة ➕المتغيّرات.

اختيار متغيّر إخراج واحد فقط مع قائمة كاملة

يمكنك ضبط SelectionInput أداة للسماح للمستخدمين باختيار متغيّر إخراج واحد من خطوة سابقة باستخدام قائمة الخيارات الإضافية.

عند ضبط SelectionInputType على OVERFLOW_MENU، تعمل الأداة المصغّرة كأداة اختيار متغيّرات مخصّصة. على عكس استخدام includeVariables مع TextInput، الذي يحوّل قيم المتغيّرات إلى سلاسل، يحتفظ OVERFLOW_MENU بنوع البيانات الأصلي للمتغيّر المحدّد.

برمجة التطبيقات

const selectionInput = CardService.newSelectionInput()
  .setFieldName("variable_picker_1")
  .setTitle("Variable Picker")
  .setType(
    CardService.SelectionInputType.OVERFLOW_MENU
  );

السماح للمستخدمين بدمج النص ومتغيرات الإخراج

يمكنك ضبط TextInput عناصر واجهة المستخدم للتحكّم في طريقة تفاعل المستخدمين مع النصوص ومتغيّرات الإخراج باستخدام setInputMode().

  • RICH_TEXT: تتيح للمستخدمين الجمع بين النص ومتغيرات الإخراج. والنتيجة هي سلسلة واحدة مدمجة.
  • PLAIN_TEXT: يقيّد الإدخال. يمكن للمستخدمين كتابة نص أو اختيار متغيّر إخراج واحد. يؤدي اختيار متغيّر إلى استبدال أي نص حالي. استخدِم هذا الوضع لفرض أنواع بيانات محدّدة تم تحديدها في ملف البيان.

تعرض الصورة التالية عنصرَي TextInput. تم ضبط الأول على RICH_TEXT ويتضمّن نصًا ومتغيرًا للناتج. يتم ضبط الخيار الثاني على PLAIN_TEXT ولا يسمح إلا بمتغيّر ناتج.

  • أدوات إدخال النص التي تم ضبطها على RICH_TEXT وPLAIN_TEXT
    الشكل 3: أدوات إدخال النص تم ضبطها على RICH_TEXT وPLAIN_TEXT.

ننصحك بضبط وضع الإدخال بشكلٍ صريح لجميع عناصر واجهة المستخدم TextInput.

في ما يلي ملف البيان لإعداد أدوات TextInput بأوضاع إدخال مختلفة:

JSON

{
  "timeZone": "America/Toronto",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Text and output variable demo",
      "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "richTextDemo",
          "state": "ACTIVE",
          "name": "Rich Text Demo",
          "description": "Show the difference between rich text and plain text TextInput widgets",
          "workflowAction": {
            "inputs": [
              {
                "id": "value1",
                "description": "First user input",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              },
              {
                "id": "value2",
                "description": "Second user input",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "onConfigFunction": "onConfiguration",
            "onExecuteFunction": "onExecution"
          }
        }
      ]
    }
  }
}

في ما يلي الرمز البرمجي لإعداد عناصر واجهة مستخدم TextInput بأوضاع إدخال مختلفة:

برمجة التطبيقات

function onConfiguration() {
  const input1 = CardService.newTextInput()
    .setFieldName("value1")
    .setId("value1")
    .setTitle("Rich Text")
    .setHostAppDataSource(
      CardService.newHostAppDataSource()
        .setWorkflowDataSource(
          CardService.newWorkflowDataSource()
            .setIncludeVariables(true)
        )
    )
    // Set input mode to RICH_TEXT to allow mixed text and variables.
    .setInputMode(CardService.TextInputMode.RICH_TEXT);

  const input2 = CardService.newTextInput()
    .setFieldName("value2")
    .setId("value2")
    .setTitle("Plain text")
    .setHostAppDataSource(
      CardService.newHostAppDataSource()
        .setWorkflowDataSource(
          CardService.newWorkflowDataSource()
            .setIncludeVariables(true)
        )
    )
    // Set input mode to PLAIN_TEXT to enforce single variable selection.
    .setInputMode(CardService.TextInputMode.PLAIN_TEXT);

  const section = CardService.newCardSection()
    .addWidget(input1)
    .addWidget(input2);

  const card = CardService.newCardBuilder()
    .addSection(section)
    .build();

  return card;
}

function onExecution(e) {
}

تخصيص أزرار أداة اختيار المتغيّرات

يمكنك تخصيص زر أداة اختيار المتغيّرات من خلال ضبط حجم الزر وتصنيفه.

حجم الزر

لضبط حجم الزر، استخدِم setVariableButtonSize() مع أحد تعدادات VariableButtonSize التالية:

  • UNSPECIFIED: القيمة التلقائية يكون الزر مضغوطًا في اللوحة الجانبية وكاملاً في السياقات الأخرى.
  • COMPACT: يعرض الزر علامة الجمع (+) فقط.
  • FULL_SIZE: يعرض الزر تصنيف النص الكامل.

تصنيف الزر

لضبط نص الزر، استخدِم setVariableButtonLabel().

مثال: تخصيص أداة اختيار المتغيّرات

يوضّح المثال التالي كيفية ضبط عناصر واجهة مستخدم TextInput بأحجام مختلفة لأزرار اختيار المتغيرات وتسمية مخصّصة.

  • تخصيص زرّ أداة اختيار المتغيّرات على الويب
    الشكل 1: تخصيص زرّ اختيار المتغيّر على الويب
  • تخصيص زرّ اختيار المتغيّر في لوحة جانبية لإحدى الإضافات
    الشكل 2: تخصيص زرّ "أداة اختيار المتغيّرات" في لوحة جانبية خاصة بإحدى الإضافات

في ما يلي ملف البيان لتخصيص أزرار أداة اختيار المتغيرات:

JSON

{
  "timeZone": "America/Los_Angeles",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/script.locale"
  ],
  "addOns": {
    "common": {
      "name": "Variable button customization",
      "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "variable_picker_customization",
          "state": "ACTIVE",
          "name": "Variable Picker demo",
          "description": "List all possible variable picker customization options",
          "workflowAction": {
            "onConfigFunction": "onUpdateCardConfigFunction",
            "onExecuteFunction": "onUpdateCardExecuteFunction"
          }
        }
      ]
    }
  }
}

إليك الرمز البرمجي لتخصيص أزرار اختيار المتغيّرات:

برمجة التطبيقات

function onUpdateCardConfigFunction(event) {
  const textInput1 = CardService.newTextInput()
    .setFieldName("value1")
    .setTitle("Regular variable picker button")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonSize(CardService.VariableButtonSize.UNSPECIFIED)
      )
    );

  const textInput2 = CardService.newTextInput()
    .setFieldName("value2")
    .setTitle("Size: Unspecified")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonSize(CardService.VariableButtonSize.UNSPECIFIED)
      )
    );

  const textInput3 = CardService.newTextInput()
    .setFieldName("value3")
    .setTitle("Size: Full size")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonSize(CardService.VariableButtonSize.FULL_SIZE)
      )
    );

  const textInput4 = CardService.newTextInput()
    .setFieldName("value4")
    .setTitle("Size: Compact")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonSize(CardService.VariableButtonSize.COMPACT)
      )
    );

  const textInput5 = CardService.newTextInput()
    .setFieldName("value5")
    .setTitle("Custom button label")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonLabel("New button label!")
      )
    );

  var cardSection = CardService.newCardSection()
    .addWidget(textInput1)
    .addWidget(textInput2)
    .addWidget(textInput3)
    .addWidget(textInput4)
    .addWidget(textInput5)
    .setId("section_1");

  var card = CardService.newCardBuilder().addSection(cardSection).build();

  return card;
}

function onUpdateCardExecuteFunction(event) {
}

ضبط الإكمال التلقائي لبيانات Google Workspace

يمكنك أيضًا ملء اقتراحات الإكمال التلقائي من البيانات المتوفرة في بيئة Google Workspace الخاصة بالمستخدم:

  • مستخدمو Google Workspace: يتم ملء قائمة المستخدمين ضمن مؤسسة Google Workspace نفسها.
  • مساحات Google Chat: يتم ملء مساحات Google Chat التي يكون المستخدم عضوًا فيها.

لضبط هذا الإعداد، عليك ضبط PlatformDataSource في أداة SelectionInput، مع تحديد WorkflowDataSourceType على أنّه USER أو SPACE.

برمجة التطبيقات

// User Autocomplete
var multiSelect2 =
  CardService.newSelectionInput()
    .setFieldName("value2")
    .setTitle("User Autocomplete")
    .setType(CardService.SelectionInputType.MULTI_SELECT)
    .setMultiSelectMaxSelectedItems(3)
    .setPlatformDataSource(
      CardService.newPlatformDataSource()
        .setHostAppDataSource(
          CardService.newHostAppDataSource()
            .setWorkflowDataSource(
              CardService.newWorkflowDataSource()
                .setIncludeVariables(true)
                .setType(CardService.WorkflowDataSourceType.USER)
            ))
    );

// Chat Space Autocomplete
var multiSelect3 =
  CardService.newSelectionInput()
    .setFieldName("value3")
    .setTitle("Chat Space Autocomplete")
    .setType(CardService.SelectionInputType.MULTI_SELECT)
    .setMultiSelectMaxSelectedItems(3)
    .setPlatformDataSource(
      CardService.newPlatformDataSource()
        .setHostAppDataSource(
          CardService.newHostAppDataSource()
            .setWorkflowDataSource(
              CardService.newWorkflowDataSource()
                .setIncludeVariables(true)
                .setType(CardService.WorkflowDataSourceType.SPACE)
            ))
    );

مثال: الجمع بين أنواع الإكمال التلقائي

يعرض المثال التالي دالة onConfig تنشئ بطاقة تحتوي على ثلاث أدوات SelectionInput، ما يوضّح ميزة الإكمال التلقائي من جهة الخادم ومن جهة المستخدم ومن جهة المساحة:

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Autocomplete Demo",
      "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "autocomplete_demo",
          "state": "ACTIVE",
          "name": "Autocomplete Demo",
          "description": "Provide autocompletion in input fields",
          "workflowAction": {
            "inputs": [
              {
                "id": "value1",
                "description": "A multi-select field with autocompletion",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "onConfigFunction": "onConfigAutocomplete",
            "onExecuteFunction": "onExecuteAutocomplete"
          }
        }
      ]
    }
  }
}

برمجة التطبيقات

function onConfigAutocompleteTest(event) {
  // Handle autocomplete request
  if (event.workflow && event.workflow.elementUiAutocomplete) {
    return handleAutocompleteRequest(event);
  }

  // Server-side autocomplete widget
  var multiSelect1 =
    CardService.newSelectionInput()
      .setFieldName("value1")
      .setTitle("Server Autocomplete")
      .setType(CardService.SelectionInputType.MULTI_SELECT)
      .setMultiSelectMaxSelectedItems(3)
      .addDataSourceConfig(
        CardService.newDataSourceConfig()
          .setRemoteDataSource(
            CardService.newAction().setFunctionName('getAutocompleteResults')
          )
      )
      .addDataSourceConfig(
        CardService.newDataSourceConfig()
          .setPlatformDataSource(
            CardService.newPlatformDataSource()
              .setHostAppDataSource(
                CardService.newHostAppDataSource()
                  .setWorkflowDataSource(
                    CardService.newWorkflowDataSource()
                      .setIncludeVariables(true)
                  ))
          )
      );

  // User autocomplete widget
  var multiSelect2 =
    CardService.newSelectionInput()
      .setFieldName("value2")
      .setTitle("User Autocomplete")
      .setType(CardService.SelectionInputType.MULTI_SELECT)
      .setMultiSelectMaxSelectedItems(3)
      .setPlatformDataSource(
        CardService.newPlatformDataSource()
          .setHostAppDataSource(
            CardService.newHostAppDataSource()
              .setWorkflowDataSource(
                CardService.newWorkflowDataSource()
                  .setIncludeVariables(true)
                  .setType(CardService.WorkflowDataSourceType.USER)
              ))
      );

  // Space autocomplete widget
  var multiSelect3 =
    CardService.newSelectionInput()
      .setFieldName("value3")
      .setTitle("Chat Space Autocomplete")
      .setType(CardService.SelectionInputType.MULTI_SELECT)
      .setMultiSelectMaxSelectedItems(3)
      .setPlatformDataSource(
        CardService.newPlatformDataSource()
          .setHostAppDataSource(
            CardService.newHostAppDataSource()
              .setWorkflowDataSource(
                CardService.newWorkflowDataSource()
                  .setIncludeVariables(true)
                  .setType(CardService.WorkflowDataSourceType.SPACE)
              ))
      );

  var sectionBuilder =
    CardService.newCardSection()
      .addWidget(multiSelect1)
      .addWidget(multiSelect2)
      .addWidget(multiSelect3);

  var card =
    CardService.newCardBuilder()
      .addSection(sectionBuilder)
      .build();
  return card;
}

function handleAutocompleteRequest(event) {
  var invokedFunction = event.workflow.elementUiAutocomplete.invokedFunction;
  var query = event.workflow.elementUiAutocomplete.query;

  if (invokedFunction != "getAutocompleteResults" || query == undefined || query == "") {
    return {};
  }

  // Query your data source to get results
  let autocompleteResponse = AddOnsResponseService.newUpdateWidget()
    .addSuggestion(
      query + " option 1",
      query + "_option1",
      false,
      "https://developers.google.com/workspace/add-ons/images/person-icon.png",
      "option 1 bottom text"
    )
    .addSuggestion(
      query + " option 2",
      query + "_option2",
      false,
      "https://developers.google.com/workspace/add-ons/images/person-icon.png",
      "option 2 bottom text"
    ).addSuggestion(
      query + " option 3",
      query + "_option3",
      false,
      "https://developers.google.com/workspace/add-ons/images/person-icon.png",
      "option 3 bottom text"
    );

  const modifyAction = AddOnsResponseService.newAction()
    .addModifyCard(
      AddOnsResponseService.newModifyCard()
        .setUpdateWidget(autocompleteResponse)
    );

  return AddOnsResponseService.newRenderActionBuilder()
    .setAction(modifyAction)
    .build();
}

التحقّق من صحة متغيّر الإدخال

من أفضل الممارسات التحقّق من أنّ المستخدم يُدخل قيمة مناسبة. راجِع مقالة التحقّق من صحة متغيّر إدخال.