Enterprise Form Builder Module

Introduction

The Form.io Enterprise Form Builder Module is a form building and form management experience that is completely embeddable within an application. This enables, for example, a SaaS product to offer a white-labeled form building and form management interface directly within the app. The Enterprise Form Builder Module supports a wide range of embedded Form.io Enterprise features, such as:

  • Form Create, List, Edit, and Delete.

  • Form Edit conflict resolution - Multiple builders can modify the same form at once.

  • Routing logic and guards - Prompt a form user with unsaved changes before navigating away from a modified form.

  • Integrated Premium Components.

  • Custom Form Builder configurations.

  • Fully customizable components and route resolvers.

How it works

The Enterprise Form Builder provides pre-defined modules, built with the most popular frameworks, that serve as a scaffold that can be used to embed form building and form management functions in a application. It accomplishes this by introducing the routing logic, resolvers, and components that are used for the common CRUD operations used when managing forms.

The following routes and components are used to achieve a full form management experience:

RouteDescriptionComponent

:host

The root path for Enterprise Form Builder Module within the application. For example, "mount" this module at the "/forms" route of the application and then :host would be "/forms".

FormsComponent - Displays the index of all forms.

:host/build

Create a new form.

FormBuildComponent - Shows the builder, with Save Form button to save the form after it has been built.

:host/:formId

The "root" path for a specific form. "formId" is the Mongo ID of the form that is currently in context.

FormComponent - Shows the navigation content for "View", "Edit" and "Delete" pages for the form in context.

:host/:formId/view

To view or use a form.

FormViewComponent - Shows the rendered form, which can also be used to use the form and create submissions.

:host/:formId/edit

To modify a form using the form builder.

FormEditComponent - Loads the form json in context into the form builder so that it can be modified.

:host/:formId/delete

Used to delete a form.

FormDeleteComponent - Shows a prompt asking the user to confirm if they want to delete the form.

:host/:formId/settings

Used to configure other metadata for the Form JSON such as title, path, name, and other settings.

FormSettingsComponent - Shows a rendered form that is used to configure the metadata for the Form JSON.

:host/:formId/conflict

Used when a form conflict is detected.

FormConflictComponent - Shows a prompt to the user that a conflict was identified and asks them what they would like to do (apply changes, or revert).

:host/:formId/submission

Mounts the "root" submission module used to manage the "data" submitted into this form.

Submission Module

Getting Started

To start using the Enterprise Form Builder Module, install the module using NPM (or Yarn) in the same as the host application.

  1. Use the following command to install the Enterprise Form Builder module, along with the Form.io Renderer which is required for the Enterprise Builder Module:

npm i --save @formio/js @formio/premium @formio/enterprise-builder

or

yarn add @formio/js @formio/premium @formio/enterprise-builder
  1. Install the framework-specific libraries as follows:

npm i --save @formio/angular

or

yarn add @formio/angular

The Enterprise Form Builder Module requires the NgModule method of Angular application structure.

When creating a new Angular application, provide the following configuration to ensure it uses the NgModule method:

ng new [appname] --standalone false --routing true

Application Configuration

To configure the Angular application to use the Enterprise Builder Module, complete the following steps:

  1. Create a configuration file in the format of EnterpriseBuilderConfig as shown below:

app.config.ts
import { EnterpriseBuilderConfig } from '@formio/enterprise-builder/angular';
export const AppConfig: EnterpriseBuilderConfig = {
  license: '-- ENTER YOUR LICENSE HERE --',
  baseUrl: 'https://forms.example.com',
  projectUrl: 'https://forms.example.com/myproject',
  tag: 'common'
};

The following configurations can be provided to the Enterprise Builder Module:

Configuration Options

PropertyDescriptionExample

license

The license for the Enterprise Form Builder module.

baseUrl

The URL for the Form.io Enterprise deployment.

https://forms.example.com

projectUrl

The Project URL to "mount" for form management within this application.

https://forms.example.com/myproject

tag

The tag to use when searching the forms in the Forms index.

common

icons

The icon class to use in the renderer.

bi - (for Bootstrap Icons)

config

An object of configurations to pass to the Formio.config SDK used to configure how the SDK operates.

showData

A boolean to enable the Submission management as part of the mounted form mangement routes and UI.

true - To show the submission management

  1. Tell the application to use this configuration when mounting the module:

  1. Set the FormioAppConfig service to use the extended EnterpriseBuilderAppConfig service, and then provide the ENTERPRISE_BUILDER_CONFIG token as follows:

app.module.ts
import { FormioAppConfig } from '@formio/angular';
import {
    EnterpriseBuilderAppConfig,
    ENTERPRISE_BUILDER_CONFIG
} from '@formio/enterprise-builder/angular';
import { AppConfig } from './app.config';

@NgModule({
    declarations: [...],
    imports: [...],
    providers: [
        ...,
        {provide: ENTERPRISE_BUILDER_CONFIG, useValue: AppConfig},
        {provide: FormioAppConfig, useClass: EnterpriseBuilderAppConfig},
        ...
    ]
})
export class AppModule {}
  1. Ensure all styles that have been added to the application are supported by the Enterprise Builder Module. By default, the Enterprise Builder Module supports Bootstrap 5. To change the CSS template, extend the components (documented further below). To enable Bootstrap, install it within the application as follows:

npm i --save bootstrap bootstrap-icons bootswatch

or

yarn add bootstrap bootstrap-icons bootswatch
  1. Configure the application to use this theme with the following code:

src/styles.scss
@import "bootstrap/scss/bootstrap.scss";
@import "bootswatch/dist/cosmo/variables";
@import "bootswatch/dist/cosmo/bootstrap";
@import "@formio/js/dist/formio.full.css";
@import "bootstrap-icons/font/bootstrap-icons.scss";

This code uses Bootswatch to enable multiple themes to pick from. Alter the theme by changing the word "cosmo" to the preferred theme.

Once the configurations and styles in place, the next objective is to set up User Authentication within the application, which will further support authentication within the project for Form Management.

User Authentication

In order to have a user manage all of the forms within a project, configure the project to have a User role that will manage the forms.

  1. Within the project, create a new role called Form Builder (refer to Roles documentation for a specific walkthrough on how to achieve this).

  1. Configure permissions within the Access settings to ensure that the Form Builder role has the following Access settings within the project:

  1. Configure the Project to add these roles to the authenticated users group. Do this using the SSO configurations, or using Form.io Authentication. Either option requires modifying the User Login form to enable this authentication.

Once the Form.io project is appropriately configured, configure authentication within the host application. For this step, please follow the following instructions:

The documentation for setting up Authentication within an Angular application can be found at the Angular Authentication Documentation.

With this route in place, application users can authenticate into the app and subsequently be authenticated into the Form.io Project with the appropriate privileges.

Application Alerts

Once Authentication is in place, the next objective is to bind the Enterprise Builder application alert system with the host application. By default, the Enterprise Builder Module uses a base service for when certain alerts are triggered within the EnterpriseBuilderAlerts service.

Typically, each application will have its own "alert" notification systems. For example, some applications will chose to use the Toastr notifications with their applications when a notification is made. The Enterprise Builder Module provides a way to inject alerts generated within the Enterprise Builder Module into the host applications notification system. To do so, refer to the following example steps:

This example uses the ngx-toastr module to add Toastr notifications to the application:

  1. Installing the module as follows:

npm i --save ngx-toastr

or

yarn add ngx-toastr
  1. Add the service to the module as follows:

import { ToastrModule, provideToastr } from 'ngx-toastr';
...
...
@NgModule({
   ...
   imports: [
      ...
      ToastrModule.forRoot(),
      ...
   ],
   providers: [
      ...
      provideToastr(),
      ...
   ],
   ...
})
export class AppModule {}
  1. Create a new wrapper Service for the EnterpriseBuilderAlerts service like so:

ng g service app.alerts
  1. Extend this service from the EnterpriseBuilderAlerts, and hook it into the ToastrService as follows:

app.alerts.service.ts
import { Injectable } from "@angular/core";
import { ToastrService } from "ngx-toastr";
import { EnterpriseBuilderAlerts, Alert } from '@formio/enterprise-builder/angular';

@Injectable({
    providedIn: 'root'
})
export class AppAlertsService extends EnterpriseBuilderAlerts {
    constructor(public toastr: ToastrService) {
        super();
    }

    override add(alert: Alert) {
        this.toastr[alert.level](alert.message, alert.title);
        super.add(alert);
    }
}
  1. Provide this in the application as follows:

app.module.ts
import { EnterpriseBuilderAlerts, ... } from '@formio/enterprise-builder/angular';
import { AppAlertsService } from './app.alerts.service';
...
@NgModule({
    ...
    providers: [
        ...
        {provide: EnterpriseBuilderAlerts, useClass: AppAlertsService},
        ...
    ],
    ...
})
export class AppModule {}

Now, any alerts triggered by the Enterprise Builder Module will show within the host application alert system, the Toastr module in this case.

Mounting the Form Management UI

Next , "mount" the Form Management UI within the host application's routing system. This allows application users to navigate to a specific route within the application to see the Form Building UI provided by the Enterprise Form Builder module. To do so, complete the following steps:

In Angular, use the @angular/router module to achieve all routing for the Enterprise Form Builder Module. To accomplish this, complete the following steps:

  1. Create a new module that will encapsulate the forms module within the Enterprise Form Builder Module, using the following CLI command:

ng g module forms
  1. Mount the FormRoutes in the RouterModule within the FormsModule using the following code:

forms/forms.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { 
  FormsModule as EnterpriseBuilderFormsModule,
  FormRoutes
} from '@formio/enterprise-builder/angular';

@NgModule({
  imports: [
    CommonModule,
    EnterpriseBuilderFormsModule,
    RouterModule.forChild(FormRoutes())
  ]
})
export class FormsModule {}

A later section will cover how all of the components at each route can be overridden and modified. For now, leave the defaults.

  1. Mount this module within the routes using the app-routing.module.ts.

app-routing.module.ts
...
const routes: Routes = [
  {
    path: 'auth',
    loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
  },
  {
    path: 'forms',
    loadChildren: () => import('./forms/forms.module').then(m => m.FormsModule)
  }
];
...
  1. Consider adding a Route Guard to the "forms" path, to ensure that the app user is authenticated before they are able to navigate to the forms path. An example of a Route Guard for authentication can be found on the Form.io Github athttps://github.com/formio/enterprise-builder/tree/main/angular/demo/src/app/auth.guard.tsAdd that guard to the 'forms' as follows:

app-routing.module.ts
...
import { AuthGuard } from './auth.guard';
const routes: Routes = [
  {
    path: 'auth',
    loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
  },
  {
    path: 'forms',
    canActivate: [AuthGuard],
    loadChildren: () => import('./forms/forms.module').then(m => m.FormsModule)
  }
];
...Angu

With the Enterprise Form Builder Module in place, navigate to the "forms" path within the host application (after authenticating) and see the full Form Building and Managemenet UI as follows:

Submission Management

By default, only the Form Management UI components are enabled. To enable the Submission management UI inside of this module, provide the following within the configurations:

app.config.ts
import { EnterpriseBuilderConfig } from '@formio/enterprise-builder/angular';
export const AppConfig: EnterpriseBuilderConfig = {
  license: '-- ENTER YOUR LICENSE HERE --',
  baseUrl: 'https://forms.example.com',
  projectUrl: 'https://forms.example.com/myproject',
  tag: 'common',
  showData: true
};

Once enabled, the following UI is now available within each Form context.

Components

The Enterprise Form Builder Module includes many different Components, mounted at different routes, that can be configured and overridden by the application embedding the module. The following components are included at the following routes:

The path of the route is determined by the host application; ":host" is used to indicate the path at which the module is mounted.

For example, if FormsModule is mounted at the "forms" path within the application, then the placeholder ":host" would be replaced with ":forms".

ComponentDescriptionRoute

FormsComponent

Provides the index of forms.

:host

FormBuildComponent

The component used to create a new form, that shows the form builder.

:host/build

FormComponent

The wrapper component for all child route components within the Form context. This provides the UI for the navigation to the "edit", "settings", etc for a specific form.

:host/:formId

FormViewComponent

The component used to view (or use) a form.

:host/:formId/view

FormEditComponent

Used to edit a form, allowing the builder to edit the current Form JSON.

:host/:formId/edit

FormDeleteComponent

Confirms and processes Form deletion.

:host/:formId/delete

FormChangesComponent

Notifies a form user that a form has been changed when they attempt to navigate away from the form context. It allows them to cancel the navigation away, or leave and cancel form changes.

:host/:formId/changes

FormConflictComponent

Shown to the user when a form conflict is identified between the form being saved to the server, and the form that already exists on the server, indicating that someone has saved the form before the user saved their version.

:host/:formId/conflict

FormSettingsComponent

Provides an interface to allow a user to modify the metadata for the current form in context such as the title, name, path, tags, etc.

:host/:formId/settings

FormSubmissionsComponent

Provides an index of the submissions for a provided form context.

:host/:formId/submission

FormSubmissionComponent

The wrapper component for a Form Submission in context. Provides the navigation UI for the other child components such as view, edit, and delete.

:host/:formId/submission/:submissionId

FormSubmissionViewComponent

The component used to view an existing submission within a form.

:host/:formId/submission/:submissionId

FormSubmissionEditComponent

Used to allow the user to edit an existing submission.

:host/:formId/submission/:submissionId/edit

FormSubmissionDeleteComponent

The component that provides an interface to the user to ask them if they wish to delete a submission or not.

:host/:formId/submission/:submissionId/delete

Overriding Components

Each component can be overridden when the Enterprise Builder Module is embedded within the application. The following process is an example of how to override one of the components for the framework:

To override the UI when a Form is being viewed, alter the FormViewComponent by extending it. To do so:

  1. Create a new component within the form module using the CLI tool as follows:

ng g component forms/view

This will create a new component within the Forms module.

  1. This component can now extend the Enterprise Form Builder FormsViewComponent as follows:

forms/view/view.component.ts
import { Component } from '@angular/core';
import { FormViewComponent } from '@formio/enterprise-builder/angular';

@Component({
  selector: 'app-view',
  templateUrl: './view.component.html',
  styleUrl: './view.component.scss'
})
export class ViewComponent extends FormViewComponent {}
  1. For the HTML, copy the existing HTML template found in the FormViewComponent by starting with the code available on the Form.io Github: https://github.com/formio/enterprise-builder/blob/main/projects/enterprise-builder/src/form/view/view.component.html

  2. Copy that code and place it in the overridden view.component.html like so:

forms/view/view.component.html
<formio [url]="service.formUrl" [form]="service.form" (submit)="onSubmit($event)" (error)="onFormError($event)"></formio>
  1. Modify the component as needed, for example:

forms/view/view.component.html
<h3>{{ service.form.title }}</h3>
<div class="bg-body rounded shadow-sm p-2">
    <formio [url]="service.formUrl" [form]="service.form" (submit)="onSubmit($event)" (error)="onFormError($event)"></formio>
</div>
  1. Tell the Enterprise Form Builder Module to use the modified component instead of the default FormViewComponent. Do this in the Forms module, where FormRoutes is mounted. This function takes a configuration; provide the form view component as follows:

form/form.module.ts
...
import { FormioEmbedModule } from '@formio/angular/embed';
import { FormsModule as EnterpriseBuilderFormsModule, FormRoutes } from '@formio/enterprise-builder/angular';
import { ViewComponent } from './view/view.component';

@NgModule({
  imports: [
    CommonModule,
    FormioEmbedModule,
    EnterpriseBuilderFormsModule,
    RouterModule.forChild(FormRoutes({
      view: ViewComponent
    }))
  ],
  declarations: [
    ViewComponent
  ]
})
export class FormsModule {}

Understanding how a single component is overridden, the following configurations can be provided to override any component within the Enterprise Form Builder Module:

FormRoutes({
    index: MyFormsComponent,                // extend FormsComponent
    build: MyFormBuildComponent,            // extend FormBuildComponent
    form: MyFormComponent,                  // extend FormComponent
    view: MyFormViewComponent,              // extend FormViewComponent
    edit: MyFormEditComponent,              // extend FormEditComponent
    delete: MyFormDeleteComponent,          // extend FormDeleteComponent
    changes: MyFormChangesComponent,        // extend FormChangesComponent
    conflict: MyFormConflictComponent,      // extend FormConflictComponent
    settings: MyFormSettingsComponent,      // extend FormSettingsComponent
    submission: {
        index: MySubmissionsComponent,      // extend FormSubmissionsComponent
        submission: MySubmissionComponent,  // extend FormSubmissionComponent
        view: MySubmissionViewComponent,    // extend FormSubmissionViewComponent
        edit: MySubmissionEditComponent,    // extend FormSubmissionEditComponent
        delete: MySubmissionDeleteComponent // extend FormSubmissionDeleteComponent
    }
})

Available Components

The following components are available:

FormsComponent

This component provides the index for the forms.

FormBuildComponent

This component is used to create new forms in your application.

FormComponent

The wrapper component for all child route components within the Form context. This provides the UI for the navigation to the "edit", "settings", etc for a specific form.

FormViewComponent

The component used to view (or use) a form.

FormEditComponent

The component used to edit a form providing the builder to edit the current Form JSON.

FormSettingsComponent

Provides an interface to allow a user to modify the metadata for the current form in context such as the title, name, path, tags, etc.

FormChangesComponent

The component shown to a user when a form has been changed and the user attempts to navigate away from the form context. It allows them to either cancel the navigation away, or cancel their form changes.

FormConflictComponent

This component is shown to the user when a form conflict has been identified between the form being saved to the server and the form that already exists on the server (meaning that someone has saved the form before the user saved their version).

FormDeleteComponent

The component used to ask the user if they wish to Delete the form, and if they confirm, performs the deletion of the form.

FormSubmissionsComponent

Provides an index of the submissions for a provided form context

FormSubmissionComponent

The wrapper component for a Form Submission in context. Provides the navigation UI for the other child components such as view, edit, and delete.

FormSubmissionViewComponent

The view component to view an existing submissions within a form.

FormSubmissionEditComponent

The component used to allow the user to edit an existing submission.

FormSubmissionDeleteComponent

The component that provides an interface to the user to ask them if they wish to delete a submission or not.

Last updated