Skip to main content

Notifications

Copilot Studio - General
Answered

How to create an adaptive Card for Multiple options?

Posted on by 71

I want to create a list of multiple options where users can select any option on a multiple choice list and get a response back based on selection. here is an example in the image. 

furqanmajeed_0-1664805719116.png

 

Categories:
  • Sharmilshah Profile Picture
    Sharmilshah 28 on at
    Re: How to create an adaptive Card for Multiple options?

    Does this solution work only with PVA premium version?

  • Gakku Profile Picture
    Gakku 20 on at
    Re: How to create an adaptive Card for Multiple options?

    @HenryJammes This has been really helpful! Is there a way of passing a record after clicking an action button? 

     

    For example I have an adaptive card with: 

    {
     type: "ActionSet",
     actions: ForAll(
     Table(ParseJSON(Topic.cdtrOutputs)),
     {
     type: "Action.Submit",
     title: Text(ThisRecord.Value.OutputCode) & " - " & Text(ThisRecord.Value.Title),
     data: {cdtrItem: Text(ThisRecord.Value)}
     }
     )
    }

     

    And in my schema:

    kind: Record
    properties:
     actionSubmitId: String
     cdtrItem:
     type:
     kind: Record

     

    But this returns Null for cdtrItem.

     

    The dataset is:

     

    [
     {
     "OutputId": 5700,
     "OutputCode": "2023-WCR-0027",
     "Title": "Weekly Report"
     },
     {
     "OutputId": 5698,
     "OutputCode": "2023-DCR-0130",
     "Title": "Daily Report"
     }
    ]
  • HenryJammes Profile Picture
    HenryJammes on at
    Re: How to create an adaptive Card for Multiple options?

    Great to hear @Anonymous – we plan to create a few MS Learn articles out of these and hopefully they will be easier to follow. Feel free to reach out by private message to share the steps that require more guidance 🙂

  • Re: How to create an adaptive Card for Multiple options?

    Excellent illustration. Despite my nil knowledge on PA, I strived to follow your guide, attempting to induce a "better solution" to my own situation. I finally got it working with numerous trial-and-error in those PA flows/external data source etc. 

    I had a breakthrough in my learning!
    Thank you so much HenryJammes!

  • HenryJammes Profile Picture
    HenryJammes on at
    Re: How to create an adaptive Card for Multiple options?

    PVA unified authoring canvas to display a dynamic adaptive card

    In this second answer, I use the unified authoring canvas to provide an example on how to present a chatbot user with an adaptive card that contains dynamic content that is retrieved from an external data source. I use Dataverse in this example, but the approach should be similar for any other data source, as I retrieve data with a Power Automate cloud flow and pass the data back to Power Virtual Agents.

     

    In Power Virtual Agents, using the unified authoring canvas:

    • I create a new topic called "Store Locations", give it a few trigger phrases, and add a Question node to ask the user "What is your city"?
      I use Power Virtual Agents' default "City" entity to automatically extract the city from a user utterance.
    • I save the response as the "UserCity" variable.
    • I save my topic.

    HenryJammes_15-1671139957781.png

     

    Before going to Power Automate (to retrieve my data) the first thing I need to do is create and design an adaptive card.

    • There are many samples available here: https://adaptivecards.io/samples/ 
    • You can then further customize samples in the adaptive card designerhttps://adaptivecards.io/designer/.
    • In my example, I create a card with a FactSet (to display the location names and address in a small table), and then add 2 ActionSet, the first one with Action.OpenUrl actions, to open a location's page in a new window, and the second one with a Action.Submit action, to submit an option as an answer from the user.

      Note: Action.Submit will need adjustments depending on where you deploy your bot. For example if you deploy it to Microsoft Teams, you'll need to add extra information in the Data payload. You can refer to this documentation for more information: Adaptive Cards actions in Microsoft Teams.

    I designed a sample card that looks like this:

    HenryJammes_0-1671201916201.png

     

    The corresponding card JSON payload is:

     

     

    {
     "type": "AdaptiveCard",
     "body": [
     {
     "type": "TextBlock",
     "size": "Medium",
     "weight": "Bolder",
     "text": "️ Our Locations in X"
     },
     {
     "type": "FactSet",
     "facts": [
     {
     "title": "Option A",
     "value": "Address 1"
     },
     {
     "title": "Option B",
     "value": "Address 2"
     }
     ]
     },
     {
     "type": "Container",
     "items": [
     {
     "type": "TextBlock",
     "text": " Open for more details",
     "wrap": true,
     "size": "Default",
     "weight": "Bolder",
     "color": "Accent",
     "isSubtle": false
     },
     {
     "type": "ActionSet",
     "actions": [
     {
     "type": "Action.OpenUrl",
     "title": " Option A",
     "url": "https://www.bing.com/search?q=Option A"
     },
     {
     "type": "Action.OpenUrl",
     "title": " Option B",
     "url": "https://www.bing.com/search?q=Option B"
     }
     ],
     "spacing": "None",
     "separator": true
     },
     {
     "type": "TextBlock",
     "text": " Select store",
     "wrap": true,
     "size": "Default",
     "weight": "Bolder",
     "color": "Accent",
     "isSubtle": false,
     "horizontalAlignment": "Left",
     "spacing": "Large"
     }
     ],
     "spacing": "Large"
     },
     {
     "type": "ActionSet",
     "actions": [
     {
     "type": "Action.Submit",
     "title": " Option A",
     "id": "A",
     "data": "Option A"
     },
     {
     "type": "Action.Submit",
     "title": " Option B",
     "id": "B",
     "data": "Option B"
     }
     ]
     }
     ],
     "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
     "version": "1.3"
    }

     

     

    To make the adaptive card dynamic, I use Power Automate to provide the various JSON arrays my card needs in the expected format. Because I have 3 datasets that are slighthly different, I create 3 array variables in my cloud flow: "List Of Accounts" for the FactSet, "List Of Accounts Actions" for the first ActionSet, and "List Of Accounts Actions Submit" for the second Action Set.

     

    From my topic in Power Virtual Agents:

    • I add a "Call an action" node
    • I select "Create a flow"

    HenryJammes_16-1671140163982.png

     

    In Power Automate:

    • I add "User City" as a text input for my flow.
    • I add 3 "Initialize variable" actions
      • integer variable "Number Of Accounts"  (I'll use it to count the number of results)
      • 3 array variables: "List Of Accounts", "List Of Accounts Actions", and "List Of Accounts Actions Submit"

    HenryJammes_0-1671209492810.png

     

    • I use the "List Rows" from the Dataverse connector to retrieve a list of Accounts with a few OData expressions to optimize my query:
      • A select expressionto only retrive the Account Name, Address 1: Street 1 and Account ID (name,address1_line1,accountid)
      • A filter expression, to only retrieve active accounts that are located in the city the user provided (address1_city eq '@{triggerBody()['text']}' and statecode eq 0)
      • An order expression, so that results are sorted alphabetically (name asc)

    HenryJammes_2-1671209820337.png

     

    Now I need to use the data returned from my query to build the various variables I want to pass back to Power Virtual Agents and to my adaptive cards in Bot Framework Composer:

    • I add an "Apply to each" action, and select the "value" output from my "List Rows" action. That way, for each returned record, the actions I add within the "Apply to each" box will be applied.
    • First, an "Increment variable" action for the "Number Of Accounts" variable, with a value set to 1.

    HenryJammes_4-1671210288211.png

    • Then 3 "Append to array variables" for my various arrays I initialized.
    • What is crucial here is to respect the JSON format that the adaptive card expects for the FactSet and the 2 ActionSet.

    HenryJammes_5-1671210448377.png

     

    • Finally, in the "Return value(s) to Power Virual Agents" step, I add 4 outputs:
      • "Number Of Accounts"
      • "List Of Accounts",
      • "List Of Accounts Actions",
      • "List Of Accounts Actions Submit"
    • For array variables, I need to transform them to text format (as they were initialized as arrays). To that end, for each of them, I go the "Expression" tab, select "string" and go back to the "Dynamic Content" tab to select the variable name, and click OK.
    • I then save my cloud flow.

    HenryJammes_0-1671210787266.png

     

    Back in Power Virtual Agents:

    • I can see my Power Automate flows has the new 4 outputs.
    • I map these with new corresponding variables.
    • I use the "NumberOfAccounts" variable in a Condition node so that I can have different user experienced if the city returns 0 results.

    HenryJammes_0-1671469146625.png

     

    Under "All other conditions", I add:

    • A "Send a message" node with a text saying "OK, I have found {x] NumberOfAccounts location(s) in {x}bot.UserCity." using variables.
    • An "Ask a question" node, where I add "Adaptive card".
    • I save the response as the UserSelectedAccount variable.

    HenryJammes_4-1671470015154.png

     

    • Under JSON, I paste the content of my adaptive card JSON payload.
    • I expand the card content,
    • I then convert the JSON to a Power Fx Formula record,
    • For each of the dynamic arrays in my adaptive card, I reference the retrieved Power Automate JSON data using Topic.VariableName within as a Power Fx record, using the ForAll, Table, and ParseJSON formulas.
    {
     type: "AdaptiveCard",
     body: [
     {
     type: "TextBlock",
     size: "Medium",
     weight: "Bolder",
     text: "🗺️ Our Locations in " & Topic.UserCity
     },
     {
     type: "FactSet",
     facts: ForAll(
     Table(ParseJSON(Topic.ListOfAccounts)),
     {
     title: Text(ThisRecord.Value.title),
     value: Text(ThisRecord.Value.value)
     }
     )
     },
     {
     type: "Container",
     items: [
     {
     type: "TextBlock",
     text: "🔎 Open for more details",
     wrap: true,
     size: "Default",
     weight: "Bolder",
     color: "Accent",
     isSubtle: false
     },
     {
     type: "ActionSet",
     actions: ForAll(
     Table(ParseJSON(Topic.ListOfAccountsActions)),
     {
     type: Text(ThisRecord.Value.type),
     title: Text(ThisRecord.Value.title),
     url: Text(ThisRecord.Value.url)
     }
     ),
     spacing: "None",
     separator: true
     },
     {
     type: "TextBlock",
     text: "👆 Select store",
     wrap: true,
     size: "Default",
     weight: "Bolder",
     color: "Accent",
     isSubtle: false,
     horizontalAlignment: "Left",
     spacing: "Large"
     }
     ],
     spacing: "Large"
     },
     {
     type: "ActionSet",
     actions: ForAll(
     Table(ParseJSON(Topic.ListOfAccountsActionsSubmit)),
     {
     type: Text(ThisRecord.Value.type),
     title: Text(ThisRecord.Value.title),
     id: Text(ThisRecord.Value.id),
     data: Text(ThisRecord.Value.data)
     }
     )
     }
     ],
     '$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
     version: "1.3"
    }

    HenryJammes_3-1671469883752.png

    I then can:

    • Add a message saying "You selected {x} UserSelectedAccount. Great choice!" using the new variable.
    • Save my topic.

    HenryJammes_5-1671470173563.png

     

    And that's it.

    The adaptive card with dynamic content is presented to the user:

    HenryJammes_6-1671470284953.png

  • Verified answer
    HenryJammes Profile Picture
    HenryJammes on at
    Re: How to create an adaptive Card for Multiple options?

    PVA + Bot Framework Composer to display a dynamic adaptive card

    For this example, I will use the current version of Power Virtual Agents that's extensible with the Bot Framework Composer. I will provide an example on how to present a chatbot user with an adaptive card that contains dynamic content that is retrieved from an external data source. I use Dataverse in this example, but the approach should be similar for any other data source, as I retrieve data with a Power Automate cloud flow and pass the data back to Power Virtual Agents.

     

    In my scenario, I start in Power Virtual Agents:

    • I create a new topic called "Store Locations" and give it a few trigger phrases.
    • I add a Question node to ask the user "What is your city"?
    • I use the default "City" entity to automatically extract the city from a user utterance.
    • I save the response as the "UserCity" variable and update the variable to make it global, so I change its scope to "Bot (any topic can access)". This is important for the rest of my demonstration because I will also pass that value to a Bot Framework Composer dialog.
    • I save my topic.

    HenryJammes_1-1671133550534.png

     

    Before going to Power Automate (to retrieve my data) or in Bot Framework Composer (to enrich my dialog with an adaptive card), the first thing I need to do is create and design an adaptive card.

    • There are many samples available here: https://adaptivecards.io/samples/ 
    • You can then further customize samples in the adaptive card designerhttps://adaptivecards.io/designer/.
    • In my example, I create a card with a FactSet (to display he location names and address in a small table), and then add 2 ActionSet, the first one with Action.OpenUrl actions, to open a location's page in a new window, and the second one with a Action.Submit action, to submit an option as an answer from the user.
      Note: Action.Submit will need adjustments depending on where you deploy your bot. For example if you deploy it to Microsoft Teams, you'll need to add extra information in the Data payload. You can refer to this documentation for more information: Adaptive Cards actions in Microsoft Teams.

    I designed a sample card that looks like this:

    HenryJammes_0-1671201916201.png

     

    The corresponding card JSON payload is:

     

     

     

     

    {
     "type": "AdaptiveCard",
     "body": [
     {
     "type": "TextBlock",
     "size": "Medium",
     "weight": "Bolder",
     "text": "️ Our Locations in X"
     },
     {
     "type": "FactSet",
     "facts": [
     {
     "title": "Option A",
     "value": "Address 1"
     },
     {
     "title": "Option B",
     "value": "Address 2"
     }
     ]
     },
     {
     "type": "Container",
     "items": [
     {
     "type": "TextBlock",
     "text": " Open for more details",
     "wrap": true,
     "size": "Default",
     "weight": "Bolder",
     "color": "Accent",
     "isSubtle": false
     },
     {
     "type": "ActionSet",
     "actions": [
     {
     "type": "Action.OpenUrl",
     "title": " Option A",
     "url": "https://www.bing.com/search?q=Option A"
     },
     {
     "type": "Action.OpenUrl",
     "title": " Option B",
     "url": "https://www.bing.com/search?q=Option B"
     }
     ],
     "spacing": "None",
     "separator": true
     },
     {
     "type": "TextBlock",
     "text": " Select store",
     "wrap": true,
     "size": "Default",
     "weight": "Bolder",
     "color": "Accent",
     "isSubtle": false,
     "horizontalAlignment": "Left",
     "spacing": "Large"
     }
     ],
     "spacing": "Large"
     },
     {
     "type": "ActionSet",
     "actions": [
     {
     "type": "Action.Submit",
     "title": " Option A",
     "id": "A",
     "data": "Option A"
     },
     {
     "type": "Action.Submit",
     "title": " Option B",
     "id": "B",
     "data": "Option B"
     }
     ]
     }
     ],
     "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
     "version": "1.3"
    }

     

     

     

     

    To make the adaptive card dynamic, I will use Power Automate to provide the various JSON arrays my card needs in the expected format. Because I have 3 datasets that are slighthly different, I will create 3 array variables in my cloud flow: "List Of Accounts" for the FactSet, "List Of Accounts Actions" for the first ActionSet, and "List Of Accounts Actions Submit" for the second Action Set.

     

    From my topic in Power Virtual Agents:

    • I add a "Call an action" node
    • I select "Create a flow"

    HenryJammes_2-1671133764441.png

     

    In Power Automate:

    • I add "User City" as a text input for my flow.
    • I add 3 "Initialize variable" actions
      • integer variable "Number Of Accounts"  (I'll use it to count the number of results)
      • 3 array variables: "List Of Accounts", "List Of Accounts Actions", and "List Of Accounts Actions Submit"

    HenryJammes_0-1671209492810.png

     

    • I use the "List Rows" from the Dataverse connector to retrieve a list of Accounts with a few OData expressions to optimize my query:
      • A select expressionto only retrive the Account Name, Address 1: Street 1 and Account ID (name,address1_line1,accountid)
      • A filter expression, to only retrieve active accounts that are located in the city the user provided (address1_city eq '@{triggerBody()['text']}' and statecode eq 0)
      • An order expression, so that results are sorted alphabetically (name asc)

    HenryJammes_2-1671209820337.png

     

    Now I need to use the data returned from my query to build the various variables I want to pass back to Power Virtual Agents and to my adaptive cards in Bot Framework Composer:

    • I add an "Apply to each" action, and select the "value" output from my "List Rows" action. That way, for each returned record, the actions I add within the "Apply to each" box will be applied.
    • First, an "Increment variable" action for the "Number Of Accounts" variable, with a value set to 1.

    HenryJammes_4-1671210288211.png

    • Then 3 "Append to array variables" for my various arrays I initialized.
    • What is crucial here is to respect the JSON format that the adaptive card expects for the FactSet and the 2 ActionSet.

    HenryJammes_5-1671210448377.png

     

    • Finally, in the "Return value(s) to Power Virual Agents" step, I add 4 outputs:
      • "Number Of Accounts"
      • "List Of Accounts",
      • "List Of Accounts Actions",
      • "List Of Accounts Actions Submit"
    • For array variables, I need to transform them to text format (as they were initialized as arrays). To that end, for each of them, I go the "Expression" tab, select "string" and go back to the "Dynamic Content" tab to select the variable name, and click OK.
    • I then save my cloud flow.

    HenryJammes_0-1671210787266.png

     

    Back in Power Virtual Agents:

    • I can see my Power Automate flows has the new 4 outputs created as variables.
    • I make the "ListOfAccounts", "ListOfAccountsActions" and "ListOfAccountsActionsSubmit" Bot-scoped variables.
    • I use the "NumberOfAccounts" variable in a Condition node so that I can have different user experienced if the city returns 0 results.
    • I save my topic

    HenryJammes_2-1671210977884.png

     

    I'm now going to move over to the Bot Framework Composer.

    • From the list of topics, I click on "Open in Bot Framework Composer".

    HenryJammes_6-1671135297639.png

    In Bot Framework Composer:

    • If I haven't done so already, I install it, authenticate and create a local folder for my changes
    • I add a new dialog for my bot that I name "ListOfAccountsAdaptiveCard

    HenryJammes_3-1671211078975.png

     

    • In order for my dialog to return values to Power Virtual Agents, I add an Output: UserSelectedAccount and it's a string.

    HenryJammes_4-1671211140419.png

     

    • Under "BeginDialog", I add a new "Ask a question" node of type "Text".
    • In the "Prompt for text" I click in the + icon and choose "Attachments", then "New attachment", "Create from template" and choose "Adaptive card"

    HenryJammes_5-1671211275231.png

    • I expand the Attachment pane and paste my adaptive card JSON card payload, in between "- ```" and "```".
    • For each place where I want my content to be dynamic, I reference the Power Virtual Agents variables using that format: ${virtualagent.VariableName}.

    HenryJammes_6-1671211522241.png

    Example:

     

     

    - ```{
     "type": "AdaptiveCard",
     "body": [
     {
     "type": "TextBlock",
     "size": "Medium",
     "weight": "Bolder",
     "text": "️ Our Locations in ${virtualagent.UserCity}"
     },
     {
     "type": "FactSet",
     "facts": ${virtualagent.ListOfAccounts}
     },
     {
     "type": "Container",
     "items": [
     {
     "type": "TextBlock",
     "text": " Open for more details",
     "wrap": true,
     "size": "Default",
     "weight": "Bolder",
     "color": "Accent",
     "isSubtle": false
     },
     {
     "type": "ActionSet",
     "actions": ${virtualagent.ListOfAccountsActions},
     "spacing": "None",
     "separator": true
     },
     {
     "type": "TextBlock",
     "text": " Select store",
     "wrap": true,
     "size": "Default",
     "weight": "Bolder",
     "color": "Accent",
     "isSubtle": false,
     "horizontalAlignment": "Left",
     "spacing": "Large"
     }
     ],
     "spacing": "Large"
     },
     {
     "type": "ActionSet",
     "actions": ${virtualagent.ListOfAccountsActionsSubmit}
     }
     ],
     "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
     "version": "1.3"
    }```

     

     

    • In "User input (Choice)", I set the "Properpty" to "dialog.result.UserSelectedAccount". That way, I am able to use the selected option in Power Virtual Agents, in a new variable.

    HenryJammes_7-1671211607527.png

    • Once done, I go to the "Publish" tab, select my bot, and click "Publish selected bots"

    HenryJammes_12-1671136795330.png

     

    I return to my Power Virtual Agents "Store Locations" topic, and under "All other conditions", I add:

    • A message saying "OK, I have found {x] NumberOfAccounts location(s) in {x}bot.UserCity." using variables.
    • A "Redirect to another topic" node to select the "ListOfAccountsAdaptiveCard" Bot Framework dialog.
    • A message saying "You selected {x} UserSelectedAccount. Great choice!" using the new variable.

    HenryJammes_8-1671211709731.png

     

    And that's it.

    The adaptive card with dynamic content is presented to the user:

     

    HenryJammes_10-1671211857125.png

  • Array of choices does not display nor taking choice does not display when re-entering the BotFramework composer dialog

    Good-day
    My bot behaves unexpectedly, sustaining the state of the first call of Array and didn't get through. I reviewed quite many times and had no clue. Appreciate any insight given.
    Details:
    1. created a PVC topic, called Main menu, redirect to a BFC dialog called BFCmainMenu

    2. created a BFC dialog, called BFCmainMenu, with:

    • set property of menu option Array
    • question in multiple choice, (Bot response/User input) set accordingly
    • branch switch inspecting the multi-choice option result to branch to corresponding dialogs (says, BFCbranchMenu) which in turn have similar setting as above hence another menu

    3. The branching dialog BFCbranchMenu mentioned at last bullet point above eventually redirect to a PVC topic

    4. The abovementioned PVC topic eventually redirect to BFCmainMenu

    However, chatbot does not display the main-Menu anymore, instead it displays the branch-Menu.

  • bikashb Profile Picture
    bikashb 23 on at
    Re: How to create an adaptive Card for Multiple options?

    I am trying the same and the only way I can think of is (if the list of items is dynamic), call Power Automate and have Power Automate generate a adaptive card with buttons. Although adaptive cards support templating / data mapping, I am not able to find a way to map buttons to a list, so right now I am composing the card json and sending that into a "Post adaptive card to MS Teams and wait for response" action. That's for teams though, but if you want generic multiple choice, then have you seen this? https://learn.microsoft.com/en-us/composer/how-to-ask-for-user-input?tabs=v2x

    Thanks!

Helpful resources

Quick Links

Welcome to the Power Platform…

We are thrilled to unveil the newly-launched Power Platform Communities!…

Getting Started…

Welcome to the Power Platform Community! We appreciate your visit…

Welcome to the new Power Platform Community!…

We are excited to announce our new Copilot Cookbook Gallery in the Community…

Leaderboard

#1
WarrenBelz Profile Picture

WarrenBelz 138,006

#2
RandyHayes Profile Picture

RandyHayes 76,308

#3
Pstork1 Profile Picture

Pstork1 63,059

Leaderboard