Skip to content

Forms

The form element enables user input, and should include submit or submitlink elements to handle that user input. When pressing such a submit button/link, data binding will be performed for all inputs in the form.

form {
  var name: String
  var pass: Secret

  label("Username:"){ input(name) }
  label("Password:"){ input(pass) }

  submit save() { "save" }
}
action save(){
  User{ 
    username := name 
    password := pass.digest()
  }.save();
}

Input

input(<expression>) creates an input form element. Can be applied directly to the properties of an entity (e.g., input(user.name)) or to page variables.

Input widgets are determined by the type of the property passed to the input template call:

  • String, Email, Int, Float, URL, Patch -> textfield
  • Text, WikiText -> textarea
  • Bool -> checkbox
  • Date, DateTime, Time -> date picker
  • [Entity], {Entity} -> multiselect (bug: List actually requires a different type of input, to allow duplicates and control ordering)
  • Entity -> select

For example, to get a checkbox, use:

page root {
 var x : Bool := false
 form{
   input(x)
   submit action{ log(x); } { "log result" }
 }
}

or:

entity TestEntity {
  x : Bool
}
template editTestEntity (e:TestEntity){
 form{
   input(e.x)
   submit action{ } { "update entity" }
 }
}

Page Variables

Page and template definitions can contain variables. This example displays "Dexter":

page cat {
  var c := Cat { name := "Dexter" }
  output(c.name)
}

entity Cat {
  name : String
}

These variables are necessary when constructing a page that creates a new entity instance. The instance can be created in the variable and data binding can be used for the input page elements. The next example allows new cat entity instances to be created, and the default name in the input form is "Dexter":

page newCat {
  var c := Cat { name := "Dexter" }
  form{
    label("Cat's name:"){ input(c.name) }
    submit action {
      c.save();
      return showCat(c);
    } { "save" }
  }
}

It is possible to initialize such a page/template variable with arbitrary statments using an 'init' action:

page newCat {
  var c
  init {
    c := Cat{};
    c.name := "Dexter";
  }
  form{
    label("Cat's name:"){ input(c.name) }
    submit action {
       c.save();
       return showCat(c);
    } { "save" }
  }
}

Be aware that these type of variables (and the init blocks) are handled separately from the other elements. They do not adhere to template control flow constructs like 'if' and 'for'; they are extracted from the definition. However, you can express such functionality in the 'init' block. For example:

error:

page bad {
  if(someConditionFunction()){
    var c := Cat{}
  }
  else {
    var c := Cat{ name := "Dexter" }
  }
  output(c.name)
}

ok:

page good {
  var c
  init{ 
    if(someConditionFunction()){
      c := Cat{}
    }
    else {
      c := Cat{ name := "Dexter" }
    }
  }
  output(c.name)
}

input for Entity

input(x, y) can be used as input for an entity variable or for a collection of entities variable, where x is the variable or fieldaccess and y is the collection of options. It will create a dropdown box/select or a multi-select respectively. The name property of an entity is used to describe the entity in a select, see Name Property.

input(x) for an entity reference property or a collection property is the same as select, with as options all entities of its type that are in the database.

Example:

entity User {
  username : String (name)
  teammate : User
  group : {Group}
}
entity Group {
  groupname : String (name)
}
init { // application init
  var u := User { username := "Alice" };
  u.save();
  u := User { username := "Bob"};
  u.save();
  var g := Group { groupname := "group 1" };
  g.save();
  g := Group { groupname := "group 2" };
  g.save();
}
page root {
  form{
    table{
      for( u: User ){
        output(u.username)
        input(u.teammate)
        input(u.group)
      }
    }
    submit action{} { "save" }
  }
}

input(u.teammate) is a dropdown/select with options null, "Alice", "Bob". input(u.group) is a multi-select with options "group 1" and "group 2".

Example 2:

page root {
  var teammates := from User
  var groups := from Group
  form{
    table{
      for(u:User){
        output(u.username)
        input(u.teammate, teammates)
        input(u.group, groups)
      }
    }
    submit action{} { "save" }
  }
}

Equivalent to the previous example, but using explicit selects instead.

Example 3:

var u3 := User { username:="Dave" }
var g3 := Group { groupname:="group 3" }

page root {
  var teammates := [u3]
  var groups := {g3}
  form{
    table{
      for(u:User){
        output(u.username)
        input(u.teammate, teammates)
        input(u.group, groups)
      }
    }
    submit action{ }{ "save" }
  }
}

Options are restricted in this example, null and "Dave" for select(u.teammate, teammates) and only "group 3" for select(u.group, groups)

Null

The null option for a select can be removed either by a not null annotation on the property:

teammate : User (not null)

Or by setting [not null] on the input or select itself:

input(u.teammate)[not null]
input(u.teammate, teammates)[not null]

Allowed

The possible options can also be determined using an annotation on the property:

group : {Group} (allowed = {g3})

In this case just using input(u.group) will only show "group 3"

Radio Buttons

Radio buttons can be used as an alternative to select for selecting an entity from a list of entities. The name property, or the property with name annotation, will be used as a label for the corresponding radio button.

entity Person {
  name   : String
  parent : Person
}

page editPerson(p:Person){
  radio(p.parent, getPersonList())
}

Captcha

The captcha element creates a fully automatic CAPTCHA form element.

Example:

page root {
  var i : Int
  form{
    input(i)
    captcha()
    submit action{ Registration{ number := i }.save(); } {"save"}
  }
}