本指南說明如何因應使用者動作 (例如點選按鈕或從選單中選取項目),動態更新設定資訊卡。
您可以插入、移除或取代資訊卡區段和小工具,建立可因應使用者輸入內容調整的彈性介面。舉例來說,如果使用者在應輸入整數的輸入欄位中輸入字串,您可以更新資訊卡介面,向使用者顯示驗證錯誤訊息,然後在使用者輸入整數後再次更新介面,隱藏該訊息。
修改資訊卡區塊和小工具
如要更新資訊方塊,小工具動作 (例如 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();
}