Dev Guide
Dev GuideUser GuideGitHubNuGetDevCommunityDoc feedbackLog In

Process forms

This topic describes how to handle and save data in Optimizely Connect Platform (OCP) submitted by users via forms.

Settings Form

While settings forms are rendered by OCP, your app is responsible for handling and saving the data submitted by the user. Your app's Lifecycle handler includes a method to handle form submission from the settings form.

When your app receives a request to handle actions on the settings form, you should use that opportunity to verify the data, perform any remote configuration required at that time, and if everything is successful, save the data to the settings store. Or if there are errors, create helpful error messages for the user.

Users can only edit one page (section) of a form at a time, so you do not have to worry about validating across pages simultaneously. However, you may wish to use configuration from other pages when validating user selections. As with any other function, you have complete access to the settings store to read any other configuration saved by the user if needed.

Response and errors

The onSettingsForm handler is expected to return a lifecycle settings result. You can provide error messages, toasts to the user, and even send them to another next section through this result.

Use addError to show an error below a particular form element or addToast to display a toast to the user.

Directing to another section

When handling a submission through onSettingsForm, you can move the user to a new form section. For example, after a user submits their credentials in an auth section, if successful, you should move them to a configuration section so they know there is more to do before the integration starts working.

if (Authorized(formData)) {
  result.addToast('success', 'Authenticated!');
  result.redirectToSettings('configure');
} else {
  result.addToast('error', 'Invalid username or password. Please check your credentials and try again.');
}

Setting the default section

The most useful section for a user to see is not always the first one. When a user opens the settings tab of your app, you may wish to show another section by default. For example, after authentication is complete, there is no reason to show the auth section even if it makes sense as the first section. You can change the default section any time by using Form.setDefaultSection

await Form.setDefaultSection('configure');

The next time the user opens the settings tab, this is the section that is open by default.

Best Practices

  • Always provide helpful information to the user in both success and error cases. For example, "Successfully scheduled your import job. You will see new data populate within the next hour." Or "Authorization successful" rather than relying on a generic success message.

  • Use form predicates to display instructions to the user. For example, you can display instructions inline in the form after authorization is complete using a visibility predicate and a page property rather than trying to provide lengthy instructions in a toast message.

  • Always save necessary form data when successful to ensure the form remains updated and the user can visually see their changes.

  • Always direct the user to the desired section. For example, authentication should be done in a separate section from other configuration/options, which allows you to send the user to the most useful section by setting the default section as well as redirecting the user after a section is completed.

Example:

/**
   * Handle a submission of a form page/section. You are responsible for performing any validation or
   * changes to the form data and then writing it to the settings store for the page.
   * @param page the name of the page/section submitted
   * @param action the action of the button that triggered the call, or 'save' by default
   * @param formData the data for the section as a hash of key/value pairs
   * @param result the response to return. Add any errors or toasts to the result before returning it.
   * @returns {LifecycleSettingsResult} with any errors that should be displayed to the user
   */
  public async onSettingsForm(
    section: string, action: string, formData: SubmittedFormData
  ): Promise<LifecycleSettingsResult> {
    const result = new LifecycleSettingsResult();
    try {
      switch (page) {
        // handle each page and action separately
        case 'authentication':
          if (await validateCredentials(formData.username, formData.password)) {
            // you can augment the form data before saving to aid form logic
            formData.authorized = true;
            // Redirect the user to the next section and let them know it was successful
            result.AddToast('success', 'Authenticated!');
            result.redirectToSettings('configure');
            await Form.setDefaultSection('configure');
          } else {
            return result
              .addError('username', 'Your username must be the email address you use to log in to <integration>')
              .addToast('error', 'Invalid username or password. Please check your credentials and try again.');
          }
          break;
      }

      // if you didn't produce any errors, you should save the form data to the settings store
      storage.settings.put(page, formData);
      return result;

    } catch (e) {
      logger.error(e);
      return result.addToast('error', 'An unexpected error occurred. Please try again at a later time');
    }
  }