3
votes

I'm using ms botbuilder v 4 I'm using webcontrol, webchat.js, latest, react Case is pretty trivial: I want to show list of possible values in dropdown, values will be dynamic (comes from API, i need Titles and Values (Ids) there. Then when user selects some item and clicks OK i want to get value (Id) and work further with that. As i got it for now only way to show dropdown is using adaptive cards, in v3 there was an option to use adaptive cards in prompts and it also planned for next version: https://github.com/Microsoft/botbuilder-dotnet/issues/1170 But for now only woraround for that is exaplained here: https://github.com/Microsoft/botbuilder-dotnet/issues/614 , with just list of string everything's working fine, but if i want to store keyvalue pairs (for IDs) i'm not able to do that cos Choices in PromptOptions only accepts list of string (will show below). So only workaround i'm using now is to store whole collection of values and after getting the result go and find it's id. Is there more convinient solution for that? Here's the code:

var choicesInputs = _teams.Select(s => new AdaptiveChoice { Title = s.Value, Value = s.Value}).ToList();

var card = new AdaptiveCard
{
    Version = new AdaptiveSchemaVersion(1, 0),
    Body =
    {
        new AdaptiveTextBlock("Select a team to assign your ticket"),
        new AdaptiveChoiceSetInput
        {
            Choices = choicesInputs,
            Id = "setId",
            Style = AdaptiveChoiceInputStyle.Compact,
            IsMultiSelect = false
        }
    },
    Actions = new List<AdaptiveAction>
    {
        new AdaptiveSubmitAction
        {
            Title = "Ok",
            Type = "Action.Submit"
        }
    }
};

signInPhoneState.Teams = _teams;

return await stepcontext.PromptAsync(
    "SelectGroupCardDialog",
    new PromptOptions
    {
            Choices = ChoiceFactory.ToChoices(_teams.Select(pair => pair.Value).ToList()),
        Prompt = (Activity) MessageFactory.Attachment(new Attachment
        {
            ContentType = AdaptiveCard.ContentType,
            Content = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(card))
        })
    },
    cancellationtoken);

// . . .

var selectedTeamId = signInPhoneState.Teams.FirstOrDefault(pair => pair.Value == sel).Key;

Quick side question (but related in terms i'm using it for workaround): What is the easiest way to persist some variable though dialog? If i remember correectly In v3 it was as simple as marking a value as public and marking dialog as serializable and that's it, now as i get it you need to create special accessor for each dialog, dublicate property there and manage the state of it, is it correct? Thanks

1
So _teams is a dictionary where the keys are team ID's and the values are team names? What you're doing seems fine, but why not just use the keys instead of the values as the AdaptiveChoice.Value properties? Then when the user submits a choice you'd get the team ID in the activity's value, right?Kyle Delaney
Are you still working on this?Kyle Delaney
@KyleDelaney hi sorry for the delay. You meant to send Id as Value? smth like this: var choicesInputs = _teams.Select(s => new AdaptiveChoice { Title = s.Value, Value = JsonConvert.SerializeObject(s)}).ToList(); ... return await stepcontext.PromptAsync( "SelectGroupCardDialog", new PromptOptions { Choices = ToChoices(_teams.Select(pair => pair.Key.ToString(),Andrey Stepanov
But in this case in response i get ONLY id and not able to get name of team, i need both. I've tried to add Synonyms, but not working, still getting Id in synonyms. Only workaround i found while we can show one value and send another then we can serialize KeyValuePair and deserialize it: var choicesInputs = _teams.Select(s => new AdaptiveChoice { Title = s.Value, Value = JsonConvert.SerializeObject(s)}).ToList(); .... return await stepcontext.PromptAsync( "SelectGroupCardDialog",Andrey Stepanov
all you mentioned is correct, all this aproaches worked when we're storing all values in external dictionary, but this is huge workaround, isn't it? To have standart key,value for dropdowns , choises, lists etc.Andrey Stepanov

1 Answers

0
votes

You have a dictionary with team ID's as keys and team names as values. You are using the team names as the values for an adaptive choice set that's being used in a prompt, and in the turn after the prompt you're extracting the team ID from the dictionary using the team name. You want a more convenient option.

Option 1: If you're okay with your current setup of keeping the dictionary available

When accessing the data in a dictionary, it is more efficient to access a value using a key than the other way around. That is what dictionaries are for, after all. So instead of using the team names as values in your choice set, you could use team ID's.

var choicesInputs = _teams.Select(s => new AdaptiveChoice { Title = s.Value, Value = s.Key }).ToList();

// . . .

signInPhoneState.Teams.TryGetValue(sel, out string selectedTeamName);

This would mean that if the dictionary is being drawn from some external source that's subject to change, the team name would be as up-to-date as possible.

Option 2: If you don't want to depend on the dictionary for the next turn

You could store both the team ID and the team name in the choice's value.

var choicesInputs = _teams.Select(s => new AdaptiveChoice { Title = s.Value, Value = JsonConvert.SerializeObject(s) }).ToList();

// . . .

var pair = JsonConvert.DeserializeObject<KeyValuePair<string, string>>(sel);
var selectedTeamId = pair.Key;
var selectedTeamName = pair.Value;

This would mean if the underlying data changes between the first turn of the prompt and the second, the choice would still be valid.