Cập nhật thẻ cấu hình

Hướng dẫn này giải thích cách cập nhật thẻ cấu hình một cách linh động để phản hồi các hành động của người dùng, chẳng hạn như nhấp vào nút hoặc chọn một mục trong trình đơn.

Bạn có thể chèn, xoá hoặc thay thế các mục và tiện ích trên thẻ để tạo giao diện thích ứng phù hợp với thông tin đầu vào của người dùng. Ví dụ: bạn có thể cập nhật giao diện thẻ để cho người dùng thấy thông báo lỗi xác thực khi họ nhập một chuỗi vào trường nhập liệu yêu cầu số nguyên, rồi cập nhật lại để ẩn thông báo sau khi người dùng nhập số nguyên.

Sửa đổi các mục và tiện ích trên thẻ

Để cập nhật thẻ, thao tác tiện ích của bạn (chẳng hạn như onClickAction) phải gọi một hàm trả về đối tượng RenderActions chứa các hướng dẫn sửa đổi.

Trên các phần của thẻ, bạn có thể thực hiện những thay đổi sau:

  • Chèn một phần: Thêm một phần vào đầu thẻ hoặc bên dưới một phần hiện có do mã nhận dạng chỉ định bằng setInsertSection.
  • Xoá một phần: Xoá một phần được chỉ định theo mã nhận dạng bằng setRemoveSection.
  • Thay thế một phần: Thay thế một phần hiện có bằng một phần mới do mã nhận dạng chỉ định bằng setReplaceSection.

Trên các tiện ích thẻ, bạn có thể thực hiện những thay đổi sau:

  • Chèn tiện ích: Thêm một tiện ích trước hoặc sau một tiện ích hiện có do mã nhận dạng chỉ định bằng setInsertWidget.
  • Xoá tiện ích: Xoá tiện ích được chỉ định theo mã nhận dạng bằng setRemoveWidget.
  • Thay thế một tiện ích: Thay thế một tiện ích hiện có bằng một tiện ích mới bằng cách nhấn vào biểu tượng setReplaceWidget.

Ví dụ: Chèn và xoá các phần cũng như tiện ích

Ví dụ sau đây tạo một thẻ cấu hình chứa các nút gọi hàm để sửa đổi thẻ bằng cách chèn hoặc xoá các tiện ích và phần.

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();
}