更新設定卡

本指南說明如何因應使用者動作 (例如點選按鈕或從選單中選取項目),動態更新設定資訊卡。

您可以插入、移除或取代資訊卡區段和小工具,建立可因應使用者輸入內容調整的彈性介面。舉例來說,如果使用者在應輸入整數的輸入欄位中輸入字串,您可以更新資訊卡介面,向使用者顯示驗證錯誤訊息,然後在使用者輸入整數後再次更新介面,隱藏該訊息。

修改資訊卡區塊和小工具

如要更新資訊方塊,小工具動作 (例如 onClickAction) 必須呼叫會傳回 RenderActions 物件的函式,該物件包含修改指示。

在資訊卡部分,您可以進行下列修改:

  • 插入區段:在卡片頂端或 ID 指定的現有區段下方,新增區段 setInsertSection
  • 移除區段:使用 setRemoveSection 移除以 ID 指定的區段。
  • 取代區段:setReplaceSection 指定 ID,將現有區段換成新區段。

在資訊卡小工具中,你可以進行下列修改:

  • 插入小工具:在現有小工具之前或之後新增小工具,並以 ID 指定小工具,方法是使用 setInsertWidget
  • 移除小工具:使用 setRemoveWidget 移除指定 ID 的小工具。
  • 取代小工具:使用新小工具取代現有小工具,並加上 setReplaceWidget

範例:插入及移除區段和小工具

下列範例會建構設定資訊卡,內含可呼叫函式的按鈕,藉此插入或移除小工具和區段,以修改資訊卡。

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Test Project",
      "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "modify_card",
          "state": "ACTIVE",
          "name": "Modify Card",
          "workflowAction": {
            "inputs": [
              {
                "id": "value1",
                "description": "The first input",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              },
              {
                "id": "value2",
                "description": "The second number",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              },
              {
                "id": "value3",
                "description": "The third number",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "outputs": [
              {
                "id": "result",
                "description": "Modify Card result",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "onConfigFunction": "onConfig",
            "onExecuteFunction": "onExecute"
          }
        }
      ]
    }
  }
}

Apps Script

// Return a configuration Card for the step.
function onConfig() {

  const textInput_1 = CardService.newTextInput().setFieldName("value1").setTitle("First Value").setId("text_input_1").setHostAppDataSource(CardService.newHostAppDataSource().setWorkflowDataSource(CardService.newWorkflowDataSource().setIncludeVariables(true)));
  const textInput_2 = CardService.newTextInput().setFieldName("value2").setTitle("Second Value").setId("text_input_2").setHostAppDataSource(CardService.newHostAppDataSource().setWorkflowDataSource(CardService.newWorkflowDataSource().setIncludeVariables(true)));

  // Create buttons that call functions to modify the card.
  const buttonSet = CardService.newButtonSet().setId("card_modification_buttons")
    .addButton(
      CardService.newTextButton()
        .setAltText("Insert Card Section")
        .setText("Insert Card Section")
        .setOnClickAction(
          CardService.newAction().setFunctionName('insertSection')
        )
    )
    .addButton(
      CardService.newTextButton()
        .setAltText("Insert Text Widget")
        .setText("Insert Text Widget")
        .setOnClickAction(
          CardService.newAction().setFunctionName('insertWidget')
        )
    );

  var firstSection =
    CardService.newCardSection()
      .setId("card_section_1")
      .addWidget(textInput_1)
      .addWidget(textInput_2)
      .addWidget(buttonSet);

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

  return card;
}

// If the step runs, return output variables.
function onExecute(event) {
  var value1 = event.workflow.actionInvocation.inputs["value1"].stringValues[0];
  var value2 = event.workflow.actionInvocation.inputs["value2"].stringValues[0];
  var value3; // Declare value3
  var result;
  // Check if the "value3" key exists in the inputs, which only exists if
  // the third text input is inserted to the Card.
  if (event.workflow.actionInvocation.inputs["value3"]) {
    value3 = event.workflow.actionInvocation.inputs["value3"].stringValues[0];

    result = value1 + "\n" + value2 + "\n" + value3;
  } else {
    result = value1 + "\n" + value2;
  }
  // Output the file ID through a variableData, which can be used by
  // later steps in a workflow.
  const variableData = AddOnsResponseService.newVariableData().addStringValue(result);

  let textFormatElement = AddOnsResponseService.newTextFormatElement().setText("Output: " + JSON.stringify(variableData));
  let workflowTextFormat = AddOnsResponseService.newWorkflowTextFormat()
  .addTextFormatElement(textFormatElement);

  // The string key for each variableData must match with the IDs of the
  // outputs defined in the manifest.
  let returnAction = AddOnsResponseService.newReturnOutputVariablesAction()
      .setVariables({ "result": variableData }).setLog(workflowTextFormat);

  let hostAppAction = AddOnsResponseService.newHostAppAction().setWorkflowAction(returnAction);

  const renderAction = AddOnsResponseService.newRenderActionBuilder()
      .setHostAppAction(hostAppAction).build();

  return renderAction;
}

/**
 * Inserts a new CardSection with several widgets.
 */
function insertSection(event) {
  console.log("event: " + JSON.stringify(event, null, 3));

  const optionalSection = CardService.newCardSection().setId("card_section_2")
    .addWidget(
      CardService.newTextParagraph().setText("This is a text paragraph inside the new card section")
    )
    .addWidget(
      CardService.newButtonSet().addButton(
        CardService.newTextButton().setText("Remove Card Section").setOnClickAction(CardService.newAction().setFunctionName("removeSection"))))
    .addWidget(
      CardService.newButtonSet().addButton(
        CardService.newTextButton().setText("Replace Card Section").setOnClickAction(CardService.newAction().setFunctionName("replaceSection"))));

  // Insert the new section beneath section "card_section_1".
  // You can also insert at the top of a Card.
  const sectionInsertion = AddOnsResponseService.newInsertSection().insertBelowSection("card_section_1").setSection(optionalSection);

  const modifyAction = AddOnsResponseService.newAction()
    .addModifyCard(AddOnsResponseService.newModifyCard().setInsertSection(sectionInsertion));

  return AddOnsResponseService.newRenderActionBuilder().setAction(modifyAction).build();
}
/**
 * Replaces an existing CardSection with a new CardSection with the same ID.
 */
function replaceSection(event) {
  console.log("event: " + JSON.stringify(event, null, 3));

  const replacementSection = CardService.newCardSection().setId("card_section_2")
    .addWidget(
      CardService.newTextParagraph().setText("Card Section replaced!")
    )
    .addWidget(
      CardService.newButtonSet().addButton(
        CardService.newTextButton().setText("Remove Card Section").setOnClickAction(CardService.newAction().setFunctionName("removeSection"))));

  const modifyAction = AddOnsResponseService.newAction()
    .addModifyCard(AddOnsResponseService.newModifyCard().setReplaceSection(replacementSection));

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

/**
* Replaces an existing CardWidget with a new CardWidget with the same ID.
*/
function replaceWidget(event) {
console.log("event: " + JSON.stringify(event, null, 3));

const replacementWidget = CardService.newTextParagraph().setText("This is a replacement widget!").setId("text_input_3");

const modifyAction = AddOnsResponseService.newAction()
  .addModifyCard(AddOnsResponseService.newModifyCard().setReplaceWidget(replacementWidget));

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

/**
 * Inserts an additional text input widget and a button that can remove it.
 */
function insertWidget(event) {
  console.log("event: " + JSON.stringify(event, null, 3));

  const buttonSet = CardService.newButtonSet().setId("widget_1")
    .addButton(
      CardService.newTextButton()
        .setAltText("Remove Widget")
        .setText("Remove Widget")
        .setOnClickAction(
          CardService.newAction().setFunctionName('removeWidget')
        ))
    .addButton(
      CardService.newTextButton()
        .setAltText("Replace Widget")
        .setText("Replace Widget")
        .setOnClickAction(
          CardService.newAction().setFunctionName('replaceWidget')
        ));

  const textInput_3 = CardService.newTextInput().setFieldName("value3").setTitle("Third Value").setId("text_input_3");

  // Widgets can be inserted either before or after another widget.
  // This example inserts a button below a text input, then inserts
  // another text input between the existing text input and the new button.
  const buttonSetInsertion = AddOnsResponseService.newInsertWidget().insertBelowWidget("text_input_2").setWidget(buttonSet);
  const textInputInsertion = AddOnsResponseService.newInsertWidget().insertAboveWidget("widget_1").setWidget(textInput_3);

  const modifyAction = AddOnsResponseService.newAction()
    .addModifyCard(AddOnsResponseService.newModifyCard().setInsertWidget(buttonSetInsertion))
    .addModifyCard(AddOnsResponseService.newModifyCard().setInsertWidget(textInputInsertion));

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

/**
 * Removes one or more existing widgets by ID.
 */
function removeWidget(event) {
  console.log("event: " + JSON.stringify(event, null, 3));

  const textInputDeletion = AddOnsResponseService.newRemoveWidget().setWidgetId("text_input_3");
  const buttonSetDeletion = AddOnsResponseService.newRemoveWidget().setWidgetId("widget_1");

  const modifyAction = AddOnsResponseService.newAction()
    .addModifyCard(
      AddOnsResponseService.newModifyCard().setRemoveWidget(textInputDeletion)
    )
    .addModifyCard(
      AddOnsResponseService.newModifyCard().setRemoveWidget(buttonSetDeletion)
    );

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

/**
 * Removes an existing card section by ID.
 */
function removeSection(event) {
  console.log("event: " + JSON.stringify(event, null, 3));

  const sectionDeletion = AddOnsResponseService.newRemoveSection().setSectionId('card_section_2');

  const modifyAction = AddOnsResponseService.newAction()
    .addModifyCard(
      AddOnsResponseService.newModifyCard().setRemoveSection(sectionDeletion)
    );

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