microsoft / BotFramework-Composer

Dialog creation and management for Microsoft Bot Framework Applications
https://docs.microsoft.com/en-us/composer/
MIT License
870 stars 372 forks source link

Combining the values of properties into a single property #8870

Closed HugzBatman19 closed 2 years ago

HugzBatman19 commented 2 years ago

To whom it may concern,

I am relatively new to Microsoft Bot Composer. I've been experimenting with adaptive expressions, arrays and objects. I am working on a prototype "Smoothie Maker" bot as an experiment that will provide a template for another work related project. Essentially, the user inputs two choices of fruit - the two user inputs are asked sequentially - both of which are stored in the property 'user.choice.first' and 'user.choice.second' respectively. Then, through 'set a property', I intended to store both of these inputs in the single property 'user.smoothie'. Then, a new dialog with a multiple options switch would start, where depending on the value of user.smoothie e.g 'Apple,Pear', it would send a response thanking the user for making that respective smoothie.

In the 'Set a Property', I tried a combination of things:

I keep getting back - Object reference not set to an instance of an object.

If anyone could provide assistant whether the above is possible in bot framework, that would be really helpful.

dinobrago commented 2 years ago

If you want an array from two properties Use Set Property in the flow as below with user.choices set to

=createArray(user.choice.first,user.choice.second)

image

dinobrago commented 2 years ago

A better way to do it would be to push the answers into an answer array when you're asking the questions. That way, you don't have to bother with choice1, choice2, ... choiceN. When you are collecting the answers in the dialog, Instead of "Set a Property", use "Edit an Array Property", type of change = push, and save each answer in an array coming out of the dialog. Then you'll have all the answers in one array and you don't have to limit their choices to an arbitrary number.

Let's say you collect the answer into dialog.answer. You can push this into dialog.answers as follows: image

dinobrago commented 2 years ago

You may have to set "always prompt" = true in the dialog configuration if you reuse, for example, "dialog.answer" to collect your information. If "dialog.answer" has a value in it , the next dialog will assume that the user has already answered the question (unless always prompt = true).

HugzBatman19 commented 2 years ago

Here is what I have whipped up so far (always prompt has been set to true) - there are two user inputs of fruit asked:

Question image

Array image

The next step is to use the array in a Switch (Multiple Options). However, the emulator stops after asking the two questions, so I believe there is an issue with the values. It only likes strings. Could I use the join() function at any point to combine all of it into a string? The emit event part is just to organise the responses in another separate dialog.

image

stevkan commented 2 years ago

@HugzBatman19, you can achieve what you are wanting thru the use of adaptive expressions prebuilt functions that are passed into the condition field of switch statement.

First, be aware that I am working from the point of the user's selections having already been stored in an array. user.answers.

This bit of code uses the prebuilt functions (if, and, and contains). Essentially, it checks the array to see if it contains any of the possible fruit combinations for a match. If a match is made, then it returns a string representing the array.

Here is the code you will want to include: if(and(contains(user.answers, "Apple"),contains(user.answers, "Pear")), "ApplePear", if(and(contains(user.answers, "Apple"),contains(user.answers, "Banana")), "AppleBanana", if(and(contains(user.answers, "Pear"),contains(user.answers, "Banana")), "PearBanana", "NoSelection")))

Here is the code broken down for readability:

if (
    and(
        contains(user.Answers, "Apple"),
        contains(user.Answers, "Pear")
    ),
    "ApplePear",
    if (
        and(
            contains(user.Answers, "Apple"),
            contains(user.Answers, "Banana")
        ),
        "AppleBanana",
        if (
            and(
                contains(user.Answers, "Pear"),
                contains(user.Answers, "Banana")
             ),
            "PearBanana",
            "NoSelection"
        )
    )
)

When a match is made in the adaptive expression based on the array ("Apple" and "Pear") and a string value is returned ("ApplePear"), that returned value is then compared against the cases in the switch statement. When a match is made in the switch, then the associated action is run.

image

image

promptValueToArray

stevkan commented 2 years ago

Closing as this should solve your issue.