简体   繁体   中英

How do you populate Adaptive Card input values on the renderer side after a selection is made in a choice set?

I am using adaptive card templating in bot framework. When user selects a particular value from a dropdown, based on the selection, few input fields on the input form card should be auto populated. How to achieve this?

Based on the dropdown, if user chooses 'myself', his email id should be auto populated in his/her email address textbox(email address I can get from user profile stored in user state). The adaptive card I am using is as below:

{
    "type": "AdaptiveCard",
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.2",
    "body": [
        {
            "type": "TextBlock",
            "text": "Please enter the email Id, on behalf of whom you want to raise the request.",
            "wrap": true
        },
        {
            "type": "Input.ChoiceSet",
            "id":"dropdown",
            "choices": [
                {
                    "title": "Myself",
                    "value": "Myself"
                },
                 {
                    "title": "Other",
                    "value": "Other"
                }
            ],
            "placeholder": "Raise request for"
        },
        {
            "type": "Input.Text",
            "id": "email",
            "placeholder": "Enter email address here",
            "validation": {
                "necessity": "Required",
                "errorMessage": "Email address is required"
            }
        },
        {
            "type": "ActionSet",
            "actions": [
                {
                    "type": "Action.Submit",
                    "title": "Submit",
                    "data": "Submit"
                }
            ]
        },
        {
            "type": "ActionSet",
            "actions": [
                {
                    "type": "Action.Submit",
                    "title": "Cancel",
                    "data": {
                        "id": "stepCancel"
                    }
                }
            ]
        }
    ]
}

I used actions instead of actionset. The card looks something like this:

{
    "type": "AdaptiveCard",
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.2",
    "body": [
        {
            "type": "TextBlock",
            "text": "Please enter the email Id, on behalf of whom you want to raise the request.",
            "wrap": true
        },
        {
            "type": "Input.ChoiceSet",
            "id": "dropdown",
            "choices": [
                {
                    "title": "Myself",
                    "value": "Myself"
                },
                {
                    "title": "Other",
                    "value": "Other"
                }
            ],
            "placeholder": "Raise request for"
        },
        {
            "type": "Input.Text",
            "id": "email",
            "placeholder": "Enter email address here",
            "validation": {
                "necessity": "Required",
                "errorMessage": "Email address is required"
            },
            "inlineAction": {
                "type": "Action.Submit",
                "title": "Submit"
            }
        }
    ]
}

If you want to get Adaptive Cards to do something they were not designed to do, you will need to write your own renderer code using Adaptive Cards extensibility . You can use this answer and its many linked answers as your guide.

相关问题

I've found that the usual pattern for these kinds of issues has two parts: come up with your own "schema" for your code to read, and then write the code to read it. If you want a choice set input to populate a certain text input with a certain value when a certain choice is selected, then your schema has three pieces of information: the text input's ID, the value to populate it with, and the choice that triggers it. Since this is a lot of information, it would be ideal if you could have all three of those pieces in their own "populate" object property like this:

{
    "type": "Input.ChoiceSet",
    "id": "dropdown",
    "choices": [
        {
            "title": "Myself",
            "value": "Myself"
        },
        {
            "title": "Other",
            "value": "Other"
        }
    ],
    "placeholder": "Raise request for",
    "populate": {
        "target": "email",
        "with": "my_email@email.com",
        "when": "Myself",
    },
},

Unfortunately, Direct Line will strip out additional properties from your Adaptive Card so they'll never reach Web Chat. There is a workaround for that problem where you can preserve your full JSON by tricking Direct Line into thinking it's not an Adaptive Card and then making sure Web Chat knows it's an Adaptive Card when it receives it.

If you don't use the workaround, you will need to find some way of getting those three pieces of information to Web Chat. If don't want your code to be reusable for different cards then you can just hardcode the name of the text input and the choice into your JavaScript so that it doesn't need to be transmitted through the card. If you go the usual route of putting the information in the id property then it could look pretty crowded, and a dynamic ID could be hard for your bot to read after the data is submitted:

"id": "populate_email_when_Myself_with_my_email@email.com",

If the user's email is already stored on the Web Chat side somehow then you won't need to transmit it through the card, and the ID could just be "populate_email_when_Myself" . That's a bit less imposing, and it would be easier for your bot to find because it's not dynamically generated. I'll go even further by assuming your client has the email address already and the text input's ID "email" is hardcoded in the JavaScript, so the choice set input ID can just be "populateEmail_Myself" .

Once you're ready to write the JavaScript code, I usually like to go with onParseElement so most of my code only gets executed at the beginning as part of a sort of initialization. However, I've discovered that a problem with onParseElement is that you'll only have access to the elements that have already been parsed, so if your text input is parsed after your choice set input then the onParseElement function for the choice set input won't have access to the text input. You could solve that problem by having the function look for an element at the very end of your card so that the function will have access to all the other elements, but my example here just uses onInputValueChanged instead of onParseElement . Note that this means the function will be executed any time any input value is changed in any card, including each time a key is pressed in a text input.

window.AdaptiveCards.AdaptiveCard.onInputValueChanged = input => {
  const PREFIX_POPULATE_EMAIL = 'populateEmail_';

  if (input.id && input.id.startsWith(PREFIX_POPULATE_EMAIL)) {
    // Myself
    const targetValue = input.id.slice(PREFIX_POPULATE_EMAIL.length);
    // The Adaptive Card object
    const card = input.getRootElement();
    // The text input with the hardcoded ID
    const emailElement = card.getElementById('email');

    // Did the user choose "Myself"?
    if (input.value == targetValue) {
      emailElement.renderedInputControlElement.value = THEIR_EMAIL_ADDRESS;
    }
  }
}

In many cases you'll need to re-render the element after you modify it by calling emailElement.render() . We don't need to do that in this case because we're changing the value in the rendered element directly with renderedInputControlElement rather than changing the value in the internal unrendered card element. This is a bit hacky because renderedInputControlElement is marked as protected in the TypeScript file, but if you wanted to do things the more official way then I suspect you'd have to rerender the whole card.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM