Skip to content

Forms

An aeppic form is a document describing the possible content (a schema) for documents based on that form. It is mostly derived from the form's definition which is written in pure text in formdown.

formdown is a dialect of markdown which is defined for the purpose of declaring forms as easily as possible.

Why a text based format ?

We chose to use text for forms as it makes versioning and understanding very easy. Visual form editors can be written on top of it though if needed. It also better aligns with the desire to keep data very open and not hidden in very technical formats.

Fields

A form is normal markdown that also supports fields. A field is marked in a similar fashion to markdown links but with square brackets.

md
[Last Name][lastName]

This defines a field called lastName using the label Last Name at that position. The field name must be a valid javascript identifier.

To define the type of a field, a separate line with a syntax similar to markdown hrefs is used. This line should reference the field and provide additional information, like the field's type.

The default type of a field is text and for simple fields this is all that is needed. The two fields definitions are actually called placeholders and the type and other data of the field is implied.

md
[Number of calls][callCount]

[callCount]: number

Here we define callCount to be of type number.

It does not matter where the field type info appears but it makes sense to keep the field type definition close to the placeholder it is used in. Usually at the end of the corresponding section or paragraph if the section is long. This is similar to how urls are referenced in markdown.

Note Number of calls is the label, callCount the field name and this can be referenced multiple times in a form.

Multiple fields can also be put next to each other in one line.

md
[First Name][firstName] [Last Name][lastName]

Sections

As with any markdown, it supports headers which are used to seperate a form into sections. The top section is called the root section. By default the root section contains all other sections, but if the top content is already a header and everything else is beneath that header level it is the root section.

md
My content

[Name][name]

# My first subsection

Some more content

# My second subsection
md
# My top header

## My subsection 1

### My subsection 3

When a document uses multiple top-level sections they are usually rendered as tabs by the form layout. Any content before the first section is part of the header.

Types

Fields can have different types. Some examples:

md
[age]: number
[birthdate]: date
[startedAt]: datetime
[address]: address
[preferredHand]: select
  - unknown
  - left
  - right
  - both
[address]: switch
...

switch

The switch type represents a boolean value. Simply true or false. It is often used to keep track of conditional values.

select

The select type represents a simple drop down box. It has a few different options depending on what is needed.

md
[preferredHand]: 
  - 
  - left
  - right
  - both

The field shows and stores either an empty string (default because its the first value) or the strings 'left', 'right', or 'both'.

It is possible to store and display different values:

md
[preferredHand]: 
  - 
  - left: Left
  - right: Right
  - both: Unknown

Where the value stored is e.g left, but the UI would show it as Left.

The initial value can also have a displayed text even if the value it an empty string in this example.

md
[preferredHand]: 
  - : Unknown 
  - left: Left
  - right: Right
  - both: Unknown

Help

A field can be associated with some text which is usually displayed via a tooltip. This is done by appending a double quoted text behind the type.

md
[age]: number "The contact's age at the time of the call"

It is also possible to provide extended help and other sections in markdown format.

md
[age]: number 
  help:
  ---
  This is some *help* text in markdown format

[flightReadiness]: select
  - DEFAULT: Nothing selected
  - GREEN: Green Contact level
  - AMBER: Free to fly anything

  help:
  ---
  This is some *help* text in markdown format

Tags

A field can also be tagged with various metadata.

md
[field with validators][fieldWithValidators]
[fieldWithValidators]: <required min-length=10>

[Sensitive Value][sensitiveField]
[sensitiveField]: <optional sensitive expiry=5-years classification=dsgvo-5>

If a field is defined twice the last one overrides the initial value

INFO

Every tag=value segment inside the <...> is available later under the placeholder and field meta information. When a value is specified it is applied as a string. When no value is specified (e.g <optional>) it is treated as a flag and its value is true. There is no automatic conversion from tag=false to boolean or anything. If the tag is unwanted remove it or handle it as a string.

There are some well known tags that have some built-in meaning.

Tag NameDescription
optionalMarks a field as optional. This means this field can be set to undefined
requiredMarks a field as required which is used by validation policies
min-lengthUsed by the validation policies
max-lengthUsed by validation policies

Validation

From a data model perspective, it usually makes sense to allow all fields to be empty when working with forms, as this increases the flexibility of workflows a lot. When important information is required before further processing either manually or by business rules any validation policies can be verified before allowing further processing.

Using the required tag (See above)

Styling Directives

Fields and sections can have certain usability and styling rules associated with it. This is done with curly braces in front of the label.

Showing and hiding fields and sections

In some scenarios, it might be necessary to show or hide fields or entire sections within a form. There are two primary mechanisms for achieving this:

  1. Show or hide values in the UI
  2. Set data fields to undefined

{show if ...} | {hidden if ...}

The styling directive placed before a field's placeholder or field definition can be configured to show or hide a field as needed.

md
# My form

[Shipping Address][shipping]

[Different Billing Address][differentBillingAddress]
[differentBillingAddress]: Switch

{show if differentBillingAddress}[Billing Address][billing]

When differentBillingAddress is false, the user-interface control for the billing address will be hidden. It's important to note that hiding the control will not reset any of the values inside it. In most use cases, this approach is sufficient, but any code relying on this information will also need to consider the status of the switch field.

Using undefined

As an alternative, a field or an entire section of fields can be marked as completely unavailable by setting their values to undefined. Fields with undefined values will not be rendered, and sections containing only undefined fields (including all subsections) will not be displayed either.

Note: Undefined fields are only allowed when the form of that document (the exact version) explicitly permits them through the allowUndefinedFields setting.

When a form includes undefined fields, it's important to ensure that all formulas can handle this situation. In particular, expressions like {show if myRefField.id} could fail if not properly handled. To address this, use the ? syntax: {show if myRefField?.id}. This approach allows the form designer to decide how to manage these cases.

You can also additionally tag those fields as optional. The default form rendering layout will use that information to allow users to show and hide such sections.

Rendering

Forms are rendered by the ae-form directive. The rendering process is explained on a conceptual level here.