Forms are common. Forms are everywhere. Forms on web sites and forms in apps. Forms can be complicated – even the simple ones. For example, when a user completes a contact form they might provide their name, address, contact details, such as email and telephone, and their actual contact message. We have multiple ways that we might take that information, such as drop down lists or simply free text boxes. Then there is the small matter of handling validation as well, required fields, fields where the value needs to be from a pre-defined set of choices and even conditional fields where if they are required is determined by the user’s previous answers.
So, what about when we need to get this type of information from a user within the context of a bot? We could build the whole conversational flow ourselves using traditional bot framework dialogs, but handling a conversation like this can be really complex. e.g. what if the user wants to go back and change a value they previously entered? The good news is that the bot framework has a fantastic way of handling this sort of guided conversation – FormFlow. With FormFlow we can define our form fields and have the user complete them, whilst getting help along the way.
In this post I will walk through what is needed to get a basic form using FormFlow working.
Building a basic form with FormFlow
Let’s look at a basic example of building a form out with FormFlow and build a simple contact form.
We start by creating a class that represents our form and create properties for each field. Form fields can be one of the following types;
- Integral – sbyte, byte, short, ushort, int, uint, long, ulong
- Floating point – float, double
- String
- DateTime
- Enum
- List of enum
In the case of field types such as integral / doubles or datetime the value a user enters will be checked when they enter it to make sure it is valid and an error message will be displayed back to the user if the value is not valid. In the case of an enum the user will be presented with only the options within the enum, via a set of buttons if the channel supports it, such as Facebook.
Once you have your fields defined, you then simply need to create a method that will return your form when called, from another dialog for example. To do this we return a new instance of the FormBuilder class and set the type of form to our ContactMessage class. Next we can define a message to be displayed to the user when the form is initiated. Finally you call the Build method which will generate the conversational flow required to complete your form.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using Microsoft.Bot.Builder.FormFlow; using System; using Microsoft.Bot.Builder.Dialogs; using System.Threading.Tasks; namespace FormFlowDemo.Models { [Serializable] public class ContactMessage { public string Name { get; set; } public string Address { get; set; } public string ContactNumber { get; set; } public string Email { get; set; } public ContactMethod PreferredContactMethod { get; set; } public string Message { get; set; } public static IForm<ContactMessage> BuildForm() { return new FormBuilder<ContactMessage>() .Message("I just need a few details to submit your message") .Build(); } } public enum ContactMethod { IGNORE, Telephone, SMS, Email } } |
Calling our Form
Now that we have our basic form, we need to call the form when our bot receives a message. To do this we need to amend our MessagesController as shown below to call our FormDialog.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public async Task<HttpResponseMessage> Post([FromBody]Activity activity) { if (activity.Type == ActivityTypes.Message) { await Conversation.SendAsync(activity, MakeRoot); } else { HandleSystemMessage(activity); } var response = Request.CreateResponse(HttpStatusCode.OK); return response; } internal static IDialog<ContactMessage> MakeRoot() { return Chain.From(() => FormDialog.FromForm(ContactMessage.BuildForm)); } |
Seeing our form running
Now that we have our basic implementation in place, if we run the bot locally in the emulator and simply say ‘hi’, this will trigger the form and start the conversational flow with the user as shown below.
As you can see the form uses the names of the properties to prompt the user for their entry and will split property names such as “contactNumber” into “contact number”. It will also use the order in which the properties are defined to determine the default order in which they are asked for.
As mentioned earlier, as we are using an enum for the preferred method of contact, the user is presented with options in the form of buttons.
Once a user has completed all of the fields on the form they are then presented with an automatically generated confirmation prompt to ensure that they are happy with their input.
At this point if the user indicated that they wanted to change their input, by answering “No”, the form will even prompt them for which field they want to change. There are also some handy commands a user can type when completing a form, including;
- quit – The form dialog is exited
- reset – The form dialog is re-started from the beginning
- help – This will present the user will help in terms of the form they are completing, such as where they are in the form and what their options are, as well as a list of other commands they can use
Summary and what’s next
This post has shown how we can build a very basic form using the default behaviour available from the FormFlow form builder. Hopefully you can see that this is already very powerful. In the next post I will dig into how we can customise our forms, showing how we can control input prompt text, validation, adding conditional fields based on the user’s input and custom confirmation messages.
Continue with part 2 of this post now to learn about customising FormFlow!
Hi i’m also anxious to learn about it, and developing my first BOT using the BOT framework.
I got stuck at a place, where using LUIS intents for formDialog to open.
Created a model class, BuildFormDelegate of Model type, and intents for it.
My first question is – Is that we need to implement for all the intents we created in LUIS?
Secondly – return Chain.From(() => new FirstLuisAttach(ModelClass.BuildForm));
code never calls the BuildForm() line of code of ModelClass.
Any message i ‘m typing in amulator giving me error..
can you please guide me.
Hi. It sounds like what you actually need is a LUIS Intent Dialog which then matches an intent and opens a child form flow dialog. Would you be able to share your code with me maybe via onedrive or dropbox and I can see what you are doing? DM me on twitter @garypretty with the details.
I would surly say thank you. All your posts including BestMatchDialog, QnAMakerDialog and FormFlow helped me a lot to under the Chatbot functionality and implementing it in my project.
I am really thankful for all you work specially the time that you are giving to community .
Thanks for the feedback!