Users can input data on cards that Chat apps receive and read. Widgets that let users enter data include:
TextInput
for free-form text entry that also supports suggestionsSelectionInput
for list items and menus, like checkboxes, radio buttons, and dropdown menusDateTimePicker
for date and time
Receiving data input by users lets Chat apps do lots of useful things, including:
- Update customer service cases
- Create work orders
- Authenticate with Web services
This guide describes how to receive and read the data that users enter in cards.
How receiving data works
A Chat app presents a card to the user as a dialog or card message.
In this example, the dialog asks the user to enter information about a contact, using TextInput
and SelectionInput
widgets. When collecting a lot of information from users, Chat apps can open sequential dialogs.
When finished, the Chat app receives the values users entered in the dialog as JSON.
Receive form data from dialogs
When users click a button on a dialog, the data that they entered gets submitted to the Chat app, and the app receives an Event
where:
EventType
isCARD_CLICKED
.DialogEventType
isSUBMIT_DIALOG
.
The data users enter in the dialog are available on the Event
as Event.common.formInputs
, a map where keys are string IDs assigned to each dialog widget and values represent user input for each widget. Different objects represent different input data types. For example, Event.common.formInputs.stringInputs
represent string inputs.
When a user submits a dialog, your Chat app receives an Event
from Google Chat, such as the following example:
JSON
{
"type": enum (EventType),
"eventTime": string,
"threadKey": string,
"message": {
object (Message)
},
"user": {
object (User)
},
"space": {
object (Space)
},
"action": {
object (FormAction)
},
"configCompleteRedirectUrl": string,
// Indicates that this event is dialog-related.
"isDialogEvent": true,
// Indicates that a user clicked a button, and all data
// they entered in the dialog is included in Event.common.formInputs.
"dialogEventType": "SUBMIT_DIALOG",
"common": {
"userLocale": string,
"hostApp": enum (HostApp),
"platform": enum (Platform),
"timeZone": {
object (TimeZone)
},
// Represents user data entered in a dialog
"formInputs": {
// Represents string data entered in a dialog, like text input fields
// and check boxes
"stringInputs": {
// An array of strings entered by the user in a dialog.
"value": [
string
]
}
},
"parameters": {
string: string,
...
},
"invokedFunction": string
}
}
Your app can access the first user-entered value at event.common.formInputs.NAME.stringInputs.value[0]
, where NAME is the name
field of a TextInput
widget.
After receiving the dialog form data, the Chat app responds by either acknowledging receipt or by returning an error, both of which are done by returning an ActionResponse
:
- To acknowledge successful receipt, respond with an
ActionResponse
that has"actionStatus": "OK"
. - To return an error, respond with an
ActionResponse
that has"actionStatus": "ERROR MESSAGE"
.
The following example checks for the presence of a name
value. If absent, the app returns an error. If present, the app acknowledges receipt of the form data and closes the dialog. If you're using Apps Script,
use the Rhino runtime and not V8.
Node.js
/**
* Checks for a form input error, the absence of
* a "name" value, and returns an error if absent.
* Otherwise, confirms successful receipt of a dialog.
*
* Confirms successful receipt of a dialog.
*
* @param {Object} event the event object from Chat API.
*
* @return {object} open a Dialog in Google Chat.
*/
function receiveDialog(event) {
// Checks to make sure the user entered a name
// in a dialog. If no name value detected, returns
// an error message.
if (event.common.formInputs.WIDGET_NAME.stringInputs.value[0] == "") {
res.json({
"actionResponse": {
"type": "DIALOG",
"dialogAction": {
"actionStatus": "Don't forget to name your new contact!"
}
}
});
// Otherwise the app indicates that it received
// form data from the dialog. Any value other than "OK"
// gets returned as an error. "OK" is interpreted as
// code 200, and the dialog closes.
} else {
res.json({
"actionResponse": {
"type": "DIALOG",
"dialogAction": {
"actionStatus": "OK"
}
}
});
}
}
Apps Script
/**
* Checks for a form input error, the absence of
* a "name" value, and returns an error if absent.
* Otherwise, confirms successful receipt of a dialog.
*
* Confirms successful receipt of a dialog.
*
* @param {Object} event the event object from Chat API.
*
* @return {object} open a Dialog in Google Chat.
*/
function receiveDialog(event) {
// Checks to make sure the user entered a name
// in a dialog. If no name value detected, returns
// an error message.
if (event.common.formInputs.WIDGET_NAME[""].stringInputs.value[0]) {
return {
"actionResponse": {
"type": "DIALOG",
"dialogAction": {
"actionStatus": "Don't forget to name your new contact!"
}
}
};
// Otherwise the app indicates that it received
// form data from the dialog. Any value other than "OK"
// gets returned as an error. "OK" is interpreted as
// code 200, and the dialog closes.
} else {
return {
"actionResponse": {
"type": "DIALOG",
"dialogAction": {
"actionStatus": "OK"
}
}
};
}
}
Python
def receive_dialog(event: Mapping[str, Any]) -> Mapping[str, Any]:
"""Checks for a form input error, the absence of a "name" value, and returns
an error if absent. Otherwise, confirms successful receipt of a dialog.
Args:
event (Mapping[str, Any]): the event object from Chat API.
Returns:
Mapping[str, Any]: the response.
"""
if common := event.get('common'):
if form_inputs := common.get('formInputs'):
if contact_name := form_inputs.get('WIDGET_NAME'):
if string_inputs := contact_name.get('stringInputs'):
if name := string_inputs.get('value')[0]:
return {
'actionResponse': {
'type': 'DIALOG',
'dialogAction': {
'actionStatus': 'OK'
}
}
}
else:
return {
'actionResponse': {
'type': 'DIALOG',
'dialogAction': {
'actionStatus': 'Don\'t forget to name your new contact!'
}
}
}