At Pulse, we have extensive experience building dynamic form based applications. Our current forms engine is deeply integrated into many of our other modules. In fact, the forms engine provides the backbone for a number of modules enabling complete control of the primary records fields, sub-fields, configuration, workflow and UI.

While it has served us and our customers well over the years, we found there were a number of aspects that we could improve upon particularly relating to administration (form design), extensibility, permission management, API access and the removal of hard limitations (number of fields etc).

To address these points, we needed to take a step back and redesign a number of components from the ground up.

Presenting the future of form designing.

Form Designer

For form design and administration, our goal was to provide our end users with an ultra-intuitive UI, one that would require no training yet didn't sacrifice any features for the sake of keeping things simple.

From the research we've done, there appears to be no existing web-based designer that could provide true drag-and-drop and drag-to-resize capabilities while also providing responsive default layouts which conform to existing web standards. Most implementations would aim to mimic drag-and-drop functionality with drag-to-reorder style approaches. Form layouts would normally be further modified by entering the desired widths for components or inserting row splitters to add columns to layouts. We wanted to avoid these unintuitive methods and build a system that acted more like a desktop based form creator but for web and mobile devices with responsive modes built-in. In order to achieve this, not only did we have to build our own custom "bootstrap-style" layout engine, but we had to develop a layout engine that could double down as a plug-in based interactive designer.

Conditional visibility example.
Responsive layouts out-of-the-box.

Technical Approach

We started by developing an interactive layout renderer in the form of a stand-alone JavaScript library. This renderer is provided with a form definition (JSON) to render form fields which can then be edited and converted back to JSON. All form fields are JavaScript components injected into the form renderer at run-time. This allows us to inject form fields relevant to the context in which the form renderer is being used to reduce the overhead in loading unused / unreferenced fields.

Form field components are simple JavaScript classes which have both standard and custom attributes, as well as functions to handle UI events. These custom attributes can be used to store additional information for the field. There is no hard limit to the amount of information which can be captured against a field.

As the form renderer is a JavaScript library, any browser based application can load and edit form definitions. In Pulse, we embed form functionality by pushing the form loading and data management responsibilities to microservices which can be used by any authenticated application.

The forms micro frontend can be embedded into any web application.

Form Data

We wanted to avoid any hard limits on the number of fields a form can have. In our older forms engine, all data was stored in a relational database. Speed was a major factor and because a form could have hundreds of fields and thousands of records, we didn't want to over-normalise the schema. The trade off meant we had to impose a hard limit on the number of available fields. However, no matter how many fields we thought would be adequate, we were often asked to increase the amount of possible fields, requiring a migration and code changes.

As the new forms engine serialises all captured data to JSON, we no longer have any strict limit on the number of fields a form can contain. The only real world limitations would be imposed by the storage mechanism. The new forms framework itself isn't intrinsically tied to any particular back-end, however we have developed forms compatible web services which store form definitions and data in MongoDB where the maximum document size is 16 MB. This could theoretically support forms with thousands of fields however this is an area we are still testing the upper bounds on.

UI Considerations
Since form data is accessible via an API there are many ways to display form records. We have build an out of-the-box record grid which caters to a majority of use cases. The record grid contains the following features:

  • Sort, reorder and filter by any field
  • Define and save custom data views
  • Export data to various formats
  • View child records as nested tables (supports multiple child records per parent record and n-level relationships)
  • Merged form type views - ability to view common fields from records of differing form types

API

The forms data service has a complete API with the ability to store and retrieve both form definitions and form data.

Documentation for the forms service can be found here: https://formservice.pulsesoftware.com/