【问题标题】:Adaptive Card clears input on submit自适应卡在提交时清除输入
【发布时间】:2020-01-12 04:00:32
【问题描述】:

我从 Microsoft Teams 机器人发送带有输入字段和 Submit 操作的 Adaptive Card。当用户单击Submit 时,我收到输入的数据,但表单字段被清除。

这是为什么?我究竟做错了什么?这种行为非常烦人,因为我无法验证输入并要求用户更正。

这发生在桌面团队应用程序、浏览器中的团队、网页中的团队网络聊天和机器人模拟器中。在 Emulator 中,让该领域失去焦点就足够了。

如果重要,我会使用 nodejs。

【问题讨论】:

  • 你愿意接受其中一个答案吗?
  • @KyleDelaney 老实说,没有。你的没有提供实际的解决方案,但作为提示很有价值,我不喜欢接受我自己的废话。
  • Stack Overflow 是关于回答问题的。你问为什么自适应卡输入被清除以及你做错了什么。你能解释一下这些问题的哪些部分没有得到回答吗?

标签: javascript node.js botframework microsoft-teams adaptive-cards


【解决方案1】:

你没有做错任何事。这就是自适应卡片在 Teams 中的工作方式,或许可以作为一种表示数据已成功发送到机器人的方式。不过,您可能可以采取一些措施来解决您的问题。

自适应卡输入字段有一个value 属性,允许您指定字段的初始值。如果您向用户发送卡片并且输入字段的value 属性已填充,则这些字段不会为空。这意味着您可以将此类卡片作为更新而不是新活动发送,并且由于 Teams 支持更新活动,因此该卡片看起来已被修改到位。如果更新使用同一张卡片但用户输入的值,那么卡片看起来保持不变,这将解决您的值消失的问题。

有一个关于向自适应卡片动态添加输入字段的问题,answer 包含保留输入字段值的示例代码:

var inputId = `text${i}`;
body.push({
    type: "Input.Text",
    id: inputId,
    value: cardData[inputId] // This is where the value is preserved
});

如果您希望使用可以安装在 NuGet 包中的预构建代码来简化整个过程,请随时在 GitHub 上表达您对这些想法的支持:
Bot.Builder.Community.AdaptiveCards
AdaptiveCard Prompt

【讨论】:

  • 谢谢凯尔。很高兴知道我没有走错路。虽然我还没有检查你答案中的所有内容,但我将我在此期间所做的事情作为答案发布。
  • @mplwork - 很高兴您设法回答了自己的问题,但支持并接受其他人为您提供的答案仍然是一种很好的礼仪
【解决方案2】:

当我在等待问题的答案时,我得出了与上面提到的 Kyle Delaney 几乎相同的结论,您必须重新发送输入的数据。

所以我开始摆弄我的代码并想出了这个解决方案,但不确定这是不是最好的方法。

作为瀑布步骤的一部分:

   async W2_showCard(step) {
        const card = CardFactory.adaptiveCard(this.makeFormCard());
        return await step.prompt('formPrompt', { prompt: MessageFactory.attachment(card) });
    }

诀窍在于formPrompt,它还确保用户提交表单而不是执行其他操作。

       // Workaround to make user click Submit or cancel dialog
        this.dialogs.add(new ActivityPrompt('formPrompt', async prompt => {

            const recognizedValue = prompt.recognized.value;
            if (recognizedValue.type === ActivityTypes.Message) {
                if (recognizedValue.value) {

                    const replyToId = recognizedValue.replyToId;

                    var oldCard = prompt.options.prompt.attachments[0];

                    var validated = true;
                    oldCard.content.body.forEach((item, i, body) => {
                        if (item.type === "Input.Text" || item.type === "Input.ChoiceSet") {

                            // preserve the user input
                            const newValue = recognizedValue.value[item.id];
                            item.value = newValue;

                            // some rudimentary input validation:
                            // assumes there is a corresponding text field just 
                            // prior to the input field (input fields 
                            // can't change their color)

                            if (newValue == '') {
                                body[i - 1].color = 'Attention';
                                body[i - 1].weight = 'Bolder';
                                validated = false;
                            } else {
                                delete body[i - 1].color;
                                delete body[i - 1].weight;
                            }
                        }
                    });

                    if( validated ) {
                        // remove the submit and cancel actions (not required, debatable)
                        delete oldCard.content.actions;
                    }

                    // update the card
                    const activity = prompt.context.activity;
                    activity.attachments = [oldCard];
                    activity.id = replyToId;
                    await prompt.context.updateActivity(activity);

                    if (validated) {
                        // this is to make input available in next waterfall step
                        prompt.recognized.value = recognizedValue.value;
                        return true;
                    } else {
                        await prompt.context.sendActivity(`Please check the form. Some values are missing`);
                    }
                } else {
                    await prompt.context.sendActivity(`Please fill out form and press *"submit"* button or type *"cancel"* to stop.`);
                }

            }
            return false;

        }));

【讨论】:

  • 嘿@mplwork,我试图复制上面的代码,就像在瀑布步骤中一样,但是我在更新活动步骤中遇到了错误。错误:活动导致多个 Skype 活动。经过进一步分析,错误出现在步骤 activity.attachments = [oldCard]; ,activity没有附件选项..有什么解决办法吗??
  • @sree 不幸的是,有些频道不支持updateActivity。 WebChat 是其中之一,Skype 显然也是。您必须捕获 updateActivity 的异常并在 catch 块中重新显示卡片。不幸的是,这会使您的聊天记录与旧卡混淆。您应该跟踪它们,否则用户可能会再次提交它们。我有完成所有这些的代码,但它与上面的代码有很大不同,所以我不能轻易地将它集成到答案中。
  • 不是其他渠道,我只是用 msteams 做的。更新活动给出了该错误。但我暂时再次使用删除活动和发送活动作为替代品。
猜你喜欢
  • 2020-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-24
  • 2020-03-29
  • 2020-06-06
  • 2013-10-16
  • 1970-01-01
相关资源
最近更新 更多