Handling boilerplate forms

For a change, this post doesn’t deal with specific code, but describes our approach to dealing with the numerous but simple edit forms that go with most enterprise web-applications.

Most business applications require a set of data, often referred to as “master data” or “static data”, which is merely a supporting cast. The true value of the business application revolves around other data structures. As an example, a financial investment tool will boast about structures like assets and portfolios. It will most likely fail to mention that the tool also manages a list of currencies, zip codes and BIC/SWIFT codes.

Usually the business application will need to allow for managing the supporting cast, but these forms should require only little effort to build, and then be low-maintenance. As the data structures are often rather simple, this calls for a generic approach.

Ad-hoc form configuration

In a web-application I developed in early 2016 using basic jQuery, Backbone.js and Handlebars.js, I ended up using the early-stage backbone-forms. The server provided a JS containing the model/form configuration, and backbone-forms dynamically created the form.

At the time the decision to have the server provide the form configuration (albeit cached client-side) was based on the benefit of deriving the configuration directly from annotations on the model. Thus adding a new persisted field and annotating the getter resulted in the field showing up on the form.

However, in a TypeScript / AOT world, this approach is not feasible.

Code generation

In funnel.travel, we still want a dynamic form creation for simple edit forms. Todd Motto has written an excellent blog post which served as a starting point. We added an additional form autocomplete component based on the blog post  by Jeff Delaney (albeit replacing anything ‘Firebase’ with standard REST queries). Another puzzle piece was to add i18n to the dynamic form.

As of writing this post, Angular 5 is still not able to use translation strings outside a template, which means the configured control labels and placeholders cannot be translated using standard Angular 5 i18n.

Our current solution has two main components.

  1. Code generation (run whenever the models change)
  2. Dynamic Angular forms

The code generation will read model data, which is annotated with Spring roles allowed to view and change each property.

@FormPropertyAccess(granted = { UserSecurityRole.SYSTEM_ADMIN, UserSecurityRole.COMMUNITY_ADMIN, UserSecurityRole.CLIENT_ADMIN })
public Userlogin setArranger(final Boolean arranger) {
    return super.setArranger(arranger);

The code generator then creates

  • A ‘codekeys.component.html’ holding all dynamic i18n keys, used by our translator service
  • An Angular model class (class Userlogin)
  • A constant instance of an empty instance of said model class (emptyUserlogin: Userlogin)
  • A form configuration listing all properties
properties = {
  email: {
    type: 'string',
    formControl: 'text',
    default: null,
    readAccess: [],
    label: 'userlogin.email',
    optional: false
  arranger: {
    type: 'boolean',
    formControl: 'slidetoggle',
    default: null,
    label: 'userlogin.arranger',
    optional: true

Dynamic forms

We’ve decided to make a few parts of the funnel.travel source code public, hosted on github. Our implementation of the “form-autocomplete” control can be found there, as an addition to and based on the blog posts mentioned above. Also, our translator service can be found there.

We haven’t done any layout work, so I’ll refrain from posting any pictures of our dynamic forms, but they are fully functional, and with only a few lines of change + running our code generation, we can:

  • add/remove model properties
  • change authorization to read/write a property

If you’d like more information, just drop us a line.


In the process of developing funnel.travel, a corporate post-booking travel management tool, I’m sharing some hopefully useful insights into Angular 4, Spring Boot, jOOQ, or any other technology we’ll be using.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s