How To Read Data On Action Buttons In Adaptive Cards

In this article, we will take a look at how we can react to the Action button in the Adaptive cards.

Introduction

In this article, we will take a look at how we can react to the Action button in the Adaptive cards. Consider an example where we want to select a color from two options and send it to the bot. Something like the following lines.
 
How to Read Data on Action Buttons in Adaptive Cards
 
In this, we want the bot to read the color selected using the radio button. We will now take a look at how to read the color.
 
Concept
 
Let us examine the adaptive card JSON definition for the above simple choice form.
  1. {  
  2.     "type""AdaptiveCard",  
  3.     "body": [  
  4.         {  
  5.             "type""TextBlock",  
  6.             "id""textBlock",  
  7.             "text""Select a Color"  
  8.         },  
  9.         {  
  10.             "type""Input.ChoiceSet",  
  11.             "placeholder""Placeholder text",  
  12.             "choices": [  
  13.                 {  
  14.                     "title""Green",  
  15.                     "value""Green"  
  16.                 },  
  17.                 {  
  18.                     "title""Red",  
  19.                     "value""Red"  
  20.                 }  
  21.             ],  
  22.             "id":"choiceset",  
  23.             "style""expanded"  
  24.         }  
  25.     ],  
  26.     "actions": [  
  27.         {  
  28.             "type""Action.Submit",  
  29.             "id""submit",  
  30.             "title""Submit",  
  31.             "data":{  
  32.                         "action""colorselector"  
  33.                   
  34.             }  
  35.         }  
  36.     ],  
  37.     "$schema""http://adaptivecards.io/schemas/adaptive-card.json",  
  38.     "version""1.0"  
  39. }  
To read more about how to desgin the adaptive cards, please visit the Adaptive Cards doco site, Adaptive Cards.
 
The adaptive card is rendered by the emulator, as shown above. Now, let us examine what we get when we select any option in the adaptive card and click on "Submit".
  1. {  
  2.   "channelData": {  
  3.     "postback"true  
  4.   },  
  5.   "channelId""emulator",  
  6.   "conversation": {  
  7.     "id""4f1c47d0-f119-11e8-bad3-4f12f90d227a|livechat"  
  8.   },  
  9.   "from": {  
  10.     "id""24474995-17e2-4290-be1f-79e27ee6140c",  
  11.     "name""User"  
  12.   },  
  13.   "id""5ce33270-f119-11e8-975a-45ab236171db",  
  14.   "localTimestamp""2018-11-26T11:49:46+10:30",  
  15.   "locale""",  
  16.   "recipient": {  
  17.     "id""15",  
  18.     "name""Bot",  
  19.     "role""bot"  
  20.   },  
  21.   "serviceUrl""http://localhost:58248",  
  22.   "timestamp""2018-11-26T01:19:46.967Z",  
  23.   "type""message",  
  24.   "value": {  
  25.     "action""colorselector",  
  26.     "choiceset""Green"  
  27.   }  
  28. }  

Above is the JSON sent by the channel to the Bot Service as a "Message Type activity" when the "submit" button is clicked. Let us examine the Value section of the message sent by the channel.

  1. "value": {  
  2.     "action""colorselector",  
  3.     "choiceset""Green"  
  4.   }  
The value object contains the following properties "action" and "choiceset". If we correlate the above with our adaptive card JSON, we can clearly see that the value in the element with id "choiceset" is appended to the data object of the submit. Once we know this, it is very easy to put in a code that can handle this. 
 
Another important point to note is that whenever the "Submit" button is clicked, the activity will be sent back by the channel as a "PostBack" if there is some reactive data in the adaptive card. If the Submit task is just sending out a string value, then it will be sent back as "ImBack".
 
Sample Code
 
Let us send the adaptive card that we have above as a welcome greeting message. Since we are just looking at a sample implementation, we will use the ConversationUpdate activity type. This activity type is emitted when a user or a bot is added to the conversation.
 
Note
Conversation Update is available in Direct Line channel only, hence exercise caution while sending out greeting messages to the user. Refer to the following post How to properly send a greeting message and common issues from customers.
 
The welcome message can be sent using following piece of code in OnTurnAsync method. 
  1. case ActivityTypes.ConversationUpdate:  
  2.                     foreach(var member in turnContext.Activity.MembersAdded)  
  3.                     {  
  4.                         if(member.Id != turnContext.Activity.Recipient.Id)  
  5.                         {  
  6.                             adaptiveCard = File.ReadAllText(@".\wwwroot\ColorSelector.json");  
  7.                             var reply = turnContext.Activity.CreateReply();  
  8.                             reply.Attachments = new List<Attachment>()  
  9.                             {  
  10.                                 new Attachment()  
  11.                                 {  
  12.                                     ContentType = "application/vnd.microsoft.card.adaptive",  
  13.                                     Content = JsonConvert.DeserializeObject(adaptiveCard)  
  14.                                 }  
  15.                             };  
  16.                             await turnContext.SendActivityAsync(reply, cancellationToken:cancellationToken);     
  17.                         }  
  18.                     }  
  19.                     break;  

Now, let us handle the scenario where the user will click on Submit. As identified above, the channel sends out the activity marked with a PostBack object.

  1. "channelData": {  
  2.     "postback"true  
  3.   }  

So, we handle the above scenario in our code as follows.

  1. case ActivityTypes.Message:  
  2.                       
  3.                     var token = JToken.Parse(turnContext.Activity.ChannelData.ToString());  
  4.                     string selectedcolor = string.Empty;  
  5.                     if(System.Convert.ToBoolean(token["postback"].Value<string>()))  
  6.                     {  
  7.                         JToken commandToken = JToken.Parse(turnContext.Activity.Value.ToString());  
  8.                         string command = commandToken["action"].Value<string>();  
  9.   
  10.                         if(command.ToLowerInvariant() == "colorselector")  
  11.                         {  
  12.                             selectedcolor = commandToken["choiceset"].Value<string>();  
  13.                         }  
  14.                           
  15.                     }  
  16.   
  17.                     await turnContext.SendActivityAsync($"You Selected {selectedcolor}", cancellationToken: cancellationToken);  
  18.   
  19.                     break;  

We are basically reading the "postback" property in the "ChannelData" object and checking if it is true. If so, we finally read the "data" object in the incoming activity and parse and take a decision based on the data. That takes care of the adaptive card submit action.

Testing
 
Let us check out a sample test scenario.
 
How to Read Data on Action Buttons in Adaptive Cards
 
Clearly, our code is now capable of handling the Submit button that sends out the selected value.
 
Tip
 
In case you are planning to use multiple reactive adaptive cards, as a best practice, the data on the Submit should have a unique identifier, e.g., Here, we added "action": "colorselector" to the data object of the "Submit" button.
 
Conclusion 
 
In this short article, we saw how to work with Reactive Adaptive Cards.