Skip to content
Roger Urscheler edited this page Apr 27, 2020 · 7 revisions

The forms feature allows sending interactive forms as part of a regular text message. When a user submits the form, the formSubmission event is raised containing the form data.

JS SDK

Posting a form

Posting a form is done by including the form attribute as part of content of the addTextItem and updateTextItem APIs.

Only one form per message is allowed. The form will be rendered after any text content as shown in the F1 Bot example above. The form will be highlighed by a left bar.

Forms can be updated using the updateTextItem API. To remove a form call updateTextItem with a form attribute that only has its id attribute defined.

The limit in the number of controls in a form is defined by the maximum size of the text item payload.

Only buttons trigger a form submission.

  // Post a form
  const item = await client.addTextItem(convId, {
    content: 'Fill out the form to register a complaint',
    form: {
      id: 'myform1234',
      title: 'Complaint Form',
      controls: [{
        type: Circuit.Enums.FormControlType.INPUT,
        name: 'issue',
        text: 'Describe the problem',
        rows: 3
      }, {
        type: Circuit.Enums.FormControlType.BUTTON,
        text: 'Send'
      }]
  });

  // Update the form
  await client.updateTextItem({
    itemId: item.itemId,
    content: 'Do you want to submit aonther complaint?',
    form: {
      id: 'myform1234',
      controls: [{
        type: Circuit.Enums.FormControlType.BUTTON,
        name: 'followup',
        options: [{
          text: 'Another one?',
          value: 'more'
        }, {
          text: `I'm done`,
          value: 'done'
        }]
      }]
    }
  });

  // Remove the form, and update the text message
  await client.updateTextItem({
    itemId: item.itemId,
    content: 'Have a nice day.',
    form: {
      id: 'myform1234'
    }];
  });

Handling submissions

The event formSubmission is raised whenever a user submits a form. Adding an event listener for the event is required as for all other events. Only the creator of the form will get the event. The event data includes the submitters userId and the form values.

A participant may submit the form multiple times. It is the responsibility of the app handling the submission to ingnore subsequent submission if needed.

Every conversation participant sees the same state of the form. That means if the app updates the form after a submission (e.g. remove the submit button), then all users will see that change. For direct conversations it may make sense to update the form based on the submission, but in group conversation less so.

  client.addEventListener('formSubmission', evt => {
    const { type, itemId, form, submitterId } = evt;
    const { id, data } = form;
    console.log(`user ${submittedId} posted form ${id}`);
    data.forEach(ctrl => console.log(`${ctrl.key}: ${ctrl.value}`));
  });

Submitting a form via SDK

Forms are usually submitted by the official Circuit clients. The SDK can also submit forms with the API submitForm.

The form.data array is identical to what the formSubmission event will receive.

  await client.submitForm(item.itemId, {
    id: 'form1234',
    data: [{
      key: 'issue',
      value: 'My PC is frozen'
    }]
  });

Form specification

The form object is made up of an id, an optional title and an array of controls.

  • id is of type string and used to identify the a particular form received in the formSubmission event
  • [title] is of type string and displayed at the top of the form
  • controls is an array of FormControls

Note: Brackets indicates attribute is optional.

The supported form controls are defined with enum Circuit.Enums.FormControlType:

  • INPUT: Input textfield. One or multiple rows
  • RADIO: List radio elements to select a single value from
  • CHECKBOX: Single or group of checkboxes
  • DROPDOWN: Dropdown list with multiple values
  • BUTTON: Single or multiple buttons
  • LABEL: Text label
  • SPACER: Separating of controls

Unless otherwise specified, all controls have the attributes:

  • type: Type of control as shown above with enum Circuit.Enums.FormControlType.
  • name: Name of the control. Applicable to submittable controls (input, radio, checkbox, dropdown). Use to identify the control in the `formSubmission event.
  • [title]: Text shown above the control.

INPUT control

Renders an input element with one or more rows.

Additional attributes:

  • [text]: Placeholder text
  • [rows]: Number of rows. If more than 1, rendered as textarea DOM element in browser.
  • [size]: Width of element. Possible values are small (25%), medium (50%) and large (100%). If more than 1 row, defaults to large, otherwise medium.

Example:

{
  type: 'INPUT',
  name: 'feedback',
  text: 'Please provide your feedback', // optional
  rows: 3,  // optional, defaults to 1
  size: 'large' // 'large' is already the default multi-row inputs
}

RADIO control

Renders a radio button set.

Additional attributes:

  • [defaultValue]: Value of radio button select by default.
  • options: Array of FormOptions. Each option defines a single radio button.
    • text: Radio button text
    • value: Radio button value of type string

Example:

{
  type: 'RADIO',
  name: 'champion',
  title: 'Who is the current F1 World Champion?', // optional
  defaultValue: '5', // optional
  options: [{
    text: 'Vettel',
    value: '5'
  }, {
    text: 'Hamilton',
    value: '44'
  }, {
    text: 'Alonso',
    value: '14'
  }]
}

CHECKBOX control

Renders a single checkbox or a set of checkboxes as single control. For set of checkboxes the options attribute is used. Defining options with a single element is identical to defining a checkbox without the options array.

Additional attributes:

  • [text]: Checkbox button text. Only for single checkbox.
  • [value]: Checkbox button value of type string. So values are 'true' or 'false'. Only for single checkbox.
  • [defaultValue]: If set to 'true', then checkbox is selected by default.
  • [options]: Array of FormOptions. Each option defines a single checkbox. Only for set of checkboxes.
    • text: Checkbox button text
    • value: Checkbox button value of type string.
    • [defaultValue]: If set to 'true', then checkbox is selected by default.

Examples:

// single checkbox
{
  type: 'CHECKBOX',
  name: 'usa_race',
  title: 'Is there an F1 race in the USA in 2018?',
  text: 'Yes',
  defaultValue: 'true'
}

// set of checkboxes
{
  type: 'CHECKBOX',
  name: 'active_drivers',
  title: 'Which are active F1 drivers?', // optional
  options: [{ // required for multi select
    text: 'Sebastian Vettel',
    value: 'vet',
    defaultValue: 'true' // optional
  }, {
    text: 'Charles Leclerc',
    value: 'lec'
  }, {
    text: 'Ayrton Senna',
    value: 'sen'
  }]
}

DROPDOWN control

Renders a dropdown control. Dependent dropdowns (where the values of a dropdown control depend on the selection of another dropdown control) is not supported.

Selecting a dropdown value does not trigger a form submission.

Additional attributes:

  • [defaultValue]: Value of dropdown selected by default.
  • options: Array of FormOptions. Each option defines an entry in the dropdown.
    • text: Dropdown item text
    • value: Dropdown item value

Example:

{
  title: 'Which is the first race of the 2018 season?',
  type: 'DROPDOWN',
  name: 'first_race',
  defaultValue: 'spa', // optional
  options: [{
    text: 'Spa',
    value: 'spa'
  }, {
    text: 'Monaco',
    value: 'monaco'
  }, {
    text: 'Melbourne',
    value: 'australia',
  }]
}

BUTTON control

Renders a single button, or a button set. Clicking any button triggers a form submission.

A button set may be used for a voting form instead of radio buttons with a submit button.

Additional attributes:

  • text: Button text
  • [action]: Action for a single button. Suported actions are:
    • submit: submits a form (default)
    • reset: resets a form to its initial state
    • submit_reset: submits a form and then resets form to initial state
  • [notification]: Notification message shown to user when performing an action (clicking a button)
  • [options]: Array of FormOptions. Each option defines a button.
    • text: Button text
    • value: Button value. Used to identify which button has been clicked.

Example:

// Single button with text 'Send' default action of 'submit'
{
  type: 'BUTTON',
  text: 'Send'
}

// Submit and reset buttons
{
  type: 'BUTTON',
  options: [{
    text: 'Submit',
    action: 'submit',
    notification: 'Form submitted successfully'
  }, {
    text: 'Cancel',
    action: 'reset'
  }]
}

// Multiple buttons used for voting (i.e. not other form controls)
{
  type: 'BUTTON',
  name: 'fruit',
  options: [{
    text: 'Apple',
    value: '1'
  }, {
    text: 'Banana asd asd asd asdsa das asd',
    value: '2'
  }, {
    text: "Strawberry",
    value: '3'
  }]
}

LABEL control

Renders a text label. Text may contain Circuit text formatting such as bold, italic or even a link.

'Thank you ...' text in image above is a label.

Label controls don't contain a value, so the name attribute is not applicable. So the only attributes are the type and text.

Additional attributes:

  • text: Label text

Example:

{
  type: 'LABEL',
  text: '<b>Total</b>: Apple (0) - Banana (3) - Strawberry (1)'
}

SPACER control

Adds extra space between controls. May be used for grouping of controls.

Spacer controls don't contain any attributes other than the type itself.

Example:

{
  type: 'SPACER'
}

REST API (swagger)

The REST API also supports sending forms and register webhooks for form submissions.

An example using the REST API to post forms and handle their submissions is the Trivia Game example. See code for form posting and webhook registration and webook handling