Good Form DSL

The basics:

  • The Good Form DSL lets you define questions.
  • A question is a form element.
  • A question can have sub elements that are displayed depending on the state of the first question.

Here is an example question:

Lets look at that DSL:
  • Line 1 defines the question reference as “G2”.
  • Line 2 defines a question “What is your name?”, which is a group of related fields (or sub questions) called Form Elements. We've called the group “names” as you can see by the group: “names”. The final attribute on line 2 is hint, which lets us put some hint text next to the question. The brace “{“ at the end of line 2 encloses the contents of the group, or the form elements that are grouped by this question.
  • Line 3 defines the first text input field form element for title. Here you can see it's a text element that is 10 characters long, has a hint, and maps to the name title. You can also see a suggest attribute that tells the form to look up title suggestions via the Simple Suggestions plugin.
  • Line 6 is a Boolean, or check box question, "Have you been or are you known by any other names?". The contained elements of this question will only be displayed if the check box is ticked.
  • Line 7 is the first contained element of "Have you been or are you known by any other names?" and it defines a listOf: “aliases” element. A listOf element, as the name suggests, creates a list of the enclosed form elements. You can add multiples of the set of form elements contained in a listOf element. If the user has only one element they fill in the displayed text fields, if they have another alias they click an add button on the form which displays a copy of the sub form for the next alias.

The map attribute of a form element provides the reference to the data within the form data map (which contains the form data). To get the title defined in this question from the form data you would use the following groovy code:

String title = formData.G2.names.title

The rendered “G2” question.

Form Element Types

The Known element types are defined in GoodFormService as: (see all form elements example at the bottom of this page)

static List knownTypes = ['text', 'date', 'datetime', 'bool', 'pick', 'group', 'listOf',
'money', 'number', 'phone', 'attachment', 'each', 'heading', 'select']

yes, those are links above


The text form element displays a text input of a defined length, e.g text: 10 which defines a text field 10 characters in length. If the length is longer than 99 then a text area will be used.


The select form element displays a select drop down using the defined choices, e.g. select: ['one','two','three'] which will display a drop down select of three items. You can define a default value and mapping.


The date form element defines a date input field with a calendar widget to select a date. The date element defines a date format to use, e.g date: “d/M/yyyy”. Date can also have max and min attributes e.g max: 'today', min: '01/01/1910' to validate against. Minimum and Maximum values are inclusive. 


The datetime form element defines a date and time input fields with calendar widget and special time entry widget. e.g. datetime: 'dd/MM/yyyy', min: '01/01/2012'


The bool form element defines a boolean element. You do not need to specify any qualifier for the boolean element so just defining a question would make it a boolean element. e.g. “Do you like nuts?” map: 'isNuts' defines a simple yes/no check box. Note that booleans that are part of a pick: 1 group need to use a pair of brackets and not define a mapping like so:

This is due to the DSL not being able to tell if it is a question or just a String when there are no attributes. By the way the above boolean elements will be rendered as a set of radio buttons and the value will be mapped to formData.G5.gender.


As we've seen above the pick form element groups a set of boolean options. You can define it as pick: 1 or pick: “any”. Pick : 1 makes a radio button group that allows you to pick one of the options. Pick: “any” lets you create group of checkboxes like so:

As you can see in the above code the boolean check boxes need to map to a particular name. To see if the applicant has ticked a Literacy problem you'd look up formData.G7.specialCircumstance.type.literacy and if

another problem not list you'd find that in formData.G7.specialCircumstance.type.other.details . The value of these booleans would be “yes” if set, or null if not set (i.e. the element wouldn't be in the formData map).


As we saw earlier the group form element just lets us group a set of elements as a set into a question. The group attribute defines the name for that group, e.g. group: “names”.


The listOf element lets you define a set of form elements that can be repeated or added as required by the user. This lets them add as many of these elements as required. the listOf attribute defines the name of the list, e.g. listOf: “aliases”. listOf elements literally create a list of answers to the question, so in the code:

If the user provides more than one alias the formData map will have a list at formData.G2.names.aliases.otherName, e.g.

formData.G2.names.aliases.otherName == ['Darth Vader','Mickey Mouse'].

You can use GoodformService.groupList() to pivot that to a List of Maps.


The money form element displays a numeric text field with preceding money symbol. You define the length of the field in number of digits including the decimal point, e.g. money: 5 would allow 99.99 or 99999. You can define a default attribute like default: 0 to set the value if not already set.


The number form element displays a numeric text field. It will be validated as a number. The element is defined with the max number of digits including decimal point, e.g. number: 5 will be ok for 12345 or 123.5 or 1.256 or -12.3. A number can also be defined with a range of numbers e.g. number: [0..20] allowing the numbers 0 to 20 to be entered.


The phone element allows numeric 'tel' type input field. The entered value will be validated against a phone number validator. You define the phone field with the number of numbers you expect, e.g. "Mobile Phone" phone: 15 which will allow for spaces, dashes or country code for example +61 418 482 545 .


The attachment form element defines a file upload element. You define the attachment element with the name of the mapping, e.g. "Attach any other documentation" attachment: "otherDocuments", this will put the upload file name reference in the otherDocument map key.


The heading element just displays a heading at the point in the form it is used. You define this element with the heading level number, e.g. “Lawyer preference” heading: 1 defines a <h1> heading.


The each form element lets you repeat the contained form elements for each item in a list stored in the form data. This data could be set after another question by the rules engine. You can inject the item into the direct sub elements question string. For example:

In this code a list of people (called fap here) is used to inject questions for each person. The {fap} in the question will substitute that name in the question.

To get the data for each of the people (faps) from the form data map you need to use a sanitised version of the persons name. To do this in the One Ring rules engine you should create a closure like this:

... and use it in a rule like this:
Back to the Good Form documentation

All form elements example

Back to the Good Form documentation

Copyright © nerdErg Pty Ltd 2012 ABN 20 159 294 989