【问题标题】:How do you populate Adaptive Card input values on the renderer side after a selection is made in a choice set?在选择集中做出选择后,如何在渲染器端填充自适应卡输入值?
【发布时间】:2021-02-01 13:59:47
【问题描述】:

我在机器人框架中使用自适应卡片模板。当用户从下拉列表中选择特定值时,根据选择,输入表单卡上的少数输入字段应自动填充。如何做到这一点?

根据下拉菜单,如果用户选择“我自己”,他的电子邮件 ID 应自动填充到他/她的电子邮件地址文本框中(我可以从存储在用户状态中的用户配置文件中获取电子邮件地址)。 我使用的自适应卡如下:

{
    "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"
                    }
                }
            ]
        }
    ]
}

我使用动作而不是动作集。卡片看起来像这样:

{
    "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 语句处理卡片的显示。我正在尝试看看这是否可能是客户端。
  • 你能告诉我们你的代码和你的自适应卡片吗?你用的是什么频道?如果您使用网络聊天,这个答案应该可以帮助您提出客户端解决方案:stackoverflow.com/questions/60877533/…
  • 你还在做这个吗?
  • 我发现了一个我认为可能对这个用例有用的功能,即使用 'Conditional layout with $when' 链接docs.microsoft.com/en-us/adaptive-cards/templating/language

标签: c# json botframework adaptive-cards web-chat


【解决方案1】:

如果您想让 Adaptive Cards 做一些他们原本不打算做的事情,您需要使用Adaptive Cards extensibility 编写您自己的渲染器代码。您可以使用this answer 及其许多链接答案作为您的指南。

我发现这类问题的常见模式有两个部分:想出您自己的“模式”供您的代码阅读,然后编写代码来阅读它。如果您希望选择集输入在选择某个选项时使用某个值填充某个文本输入,那么您的架构具有三条信息:文本输入的 ID、填充它的值以及触发的选项它。由于这是很多信息,如果您可以将所有这三个部分都放在它们自己的“填充”对象属性中,那将是理想的,如下所示:

{
    "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",
    },
},

很遗憾,Direct Line 会从您的自适应卡中删除其他属性,因此它们将永远无法访问网络聊天。针对该问题有一个workaround,您可以通过诱使 Direct Line 认为它不是自适应卡片并确保网络聊天在收到它时知道它是自适应卡片来保留完整的 JSON。

如果您不使用该解决方法,您将需要找到某种方法将这三条信息获取到网络聊天中。如果不希望您的代码可用于不同的卡片,那么您可以将文本输入的名称和选项硬编码到您的 JavaScript 中,这样就不需要通过卡片进行传输。如果您按照通常的方式将信息放在id 属性中,那么它可能看起来非常拥挤,并且在提交数据后,您的机器人可能难以读取动态 ID:

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

如果用户的电子邮件已经以某种方式存储在网络聊天端,那么您不需要通过卡传输它,ID 可能只是"populate_email_when_Myself"。这不那么令人印象深刻,并且您的机器人更容易找到它,因为它不是动态生成的。我将进一步假设您的客户已经拥有电子邮件地址并且文本输入的 ID "email" 在 JavaScript 中是硬编码的,因此选择集输入 ID 可以只是 "populateEmail_Myself"

一旦您准备好编写 JavaScript 代码,我通常喜欢使用onParseElement,因此我的大部分代码仅在开始时作为某种初始化的一部分执行。但是,我发现onParseElement 的一个问题是您只能访问已解析的元素,因此如果您的文本输入在您的选择集输入之后被解析,那么选择集输入的onParseElement 函数将无法访问文本输入。您可以通过让函数在卡片的最末端查找一个元素来解决该问题,以便该函数可以访问所有其他元素,但我这里的示例只使用onInputValueChanged 而不是onParseElement。请注意,这意味着该函数将在任何卡中的任何输入值发生更改时执行,包括每次在文本输入中按下一个键时。

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;
    }
  }
}

在许多情况下,您需要在调用emailElement.render() 修改元素后重新渲染元素。在这种情况下我们不需要这样做,因为我们直接使用renderedInputControlElement 更改渲染元素中的值,而不是更改内部未渲染卡片元素中的值。这有点 hacky,因为 renderedInputControlElement 在 TypeScript 文件中被标记为受保护,但如果你想以更正式的方式做事,那么我怀疑你必须重新渲染整个卡片。

【讨论】:

    猜你喜欢
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-18
    • 2020-01-19
    • 2020-12-03
    相关资源
    最近更新 更多