Binding

Bindings are where you specify data types, constraints, branching, and any other form logic. An example is shown below.

<bind nodeset="/data/branch" type="select1"/>
<bind nodeset="/data/mystring" type="string"
  relevant="selected(/widgets/branch, 'n')"/>

Below is a table of the supported keywords and operators. Our documentation may fall out of date, so you are a developer, you can get a more updated list in the JavaRosa source code.

Keyword

keyword usage
nodeset Specify which instance element this binding is referring to
relevant relevancy is how to branch through a form. If a node is not relevant, it doesn't appear to the user
readonly If a node is read only, the user will only be able to view that prompt, not enter data
required A required field will not allow a blank or empty answer before proceeding
constraint constraint allows you to specify acceptable answers for the specified prompt
type data type
calculate allows you to run a calculation using this and/or other answers
jr:constraingMsg The message that will be displayed if the specified constraint is violated
jr:preload javarosa provides preloaders that can automatically give you information about the form. these are discussed below
jr:preloadParams parameters used by jr:preload
jr:count references a number used to determine number of repeats. Only used in the <body>

Operators

operator usage example notes
this current prompt's answer . constraint=". < 10.51" if current answer is less than 10.51
not not(expression) relevant="not(selected(/widgets/select1, 'c'))" as long as 'c' is not selected in /widgets/select1
and and constraint="selected(., 'c') and selected(., 'd')" both 'c' and 'd' need to be selected in the current prompt
or or constraint="selected(., 'c') or selected(., 'd')" either 'c' or 'd' needs to be selected in the current prompt
greater than > constraint=". > 10.51" greater than 10.51, can also be combined with equals: >=
less than < constraint=". < 10.51" less than 10.51, can also be combined with equals: <=
selected selected(xpath/to/node, value) relevant="selected(/widgets/branch, 'n')" checks if answer in selected prompt is selected
true true() required="true()"
false false() required="false()"
regular expression regex(expression) constraint="regex(., '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}')" this particular regex checks for a valid email address
equal to = constraint=". = number('10')" current answer must be equal to 10
convert to boolean boolean (xpath/to/node or value) relevant="boolean(/widgets/branch)" conversion varies depending on data type of x
convert to number number (xpath/to/node or value) constraint=". < number(/data/age)" conversion varies depending on data type of x
convert to string string (xpath/to/node or value) "string (/data/age)" conversion varies depending on data type of x
convert to date date (xpath/to/node or value) constraint=". >= date('2011-11-12')" conversion varies depending on data type of x. format is yyyy-mm-dd
boolean from string boolean-from-string(xpath/to/node) boolean (xpath/to/node) returns true if x is "true" or "1", false otherwise. note that this is different behavior than boolean(x)
conditional if(condition, a, b) calculate="if(selected(/data/q1, 'yes') and selected(/data/q2, 'yes'), 'yes', 'no')" if true return a, else return b
count selected count-selected(xpath/to/value) count-selected(multi-select) return the number of selected answers
count(nodeset) count(nodeset) count(nodeset) count the number of nodes in nodeset
sum(nodeset) sum(nodeset) sum(nodeset) return the sum of the values of the nodes in nodeset
today() today() today() return today's date
now() now() now() return a timestamp for this instant
at least X of, at most X of checklist(min, max, v1, v2, v3, ..., vn) checklist(min, max, v1, v2, v3, ..., vn) v1 through vn are a set of n yes/no answers. return true if the count of 'yes' is between min and max, inclusive. min or max may each be -1 to indicate 'not applicable'.


Below are common examples of bindings that may be useful.

Simple String

<bind nodeset="/widgets/mystring" type="string"/>

Required Integer

<bind nodeset="/widgets/int" type="int" required="true()"/>

Branching: Show this prompt if the answer to /widget/int is less than 8

<bind nodeset="/widgets/int2" type="int" relevant="/widgets/int < 8"/>

Branching: Show this prompt if the answer to /widget/branch (a select1) is "n"

<!-- the value 'n' is the <value>, not the <label> in
  the <item> in the select or select1 -->
<bind nodeset="/widgets/language" type="string"
  relevant="selected(/widgets/branch, 'n')"/>

Constraints: Answer must be after date set in /widgets/date1

<bind nodeset="/widgets/date2" type="date"
  constraint=". >= /widgets/date"
  jr:constraintMsg="date must be after /widgets/date"/>

Constraints: Answer must be after today

<bind nodeset="/widgets/date" type="date"
  constraint=". >= today()"
  jr:constraintMsg="only future dates allowed"/>

Constraints: Answer must between 1 and 10 characters long (inclusive)

<bind nodeset="/widgets/string"
   type="string" constraint="(regex(., "^.{1,10}$"))"/>

Constraints: "c" and "d" cannot be selected at the same time

<bind nodeset="/widgets/select" type="select"
  constraint="not(selected(., 'c') and selected(., 'd'))"
  jr:constraintMsg="option c and d cannot be selected together"/>

Constraints: Multi-lingual constraint message

<!-- use itext to define various language text -->
<bind nodeset="/data/prompt" type="int" constraint=". lt;= 10"
    jr:constraintMsg="jr:itext('/data/prompt:error_message')"/>

Regular Expression: Answer must be an email address like bob@aol.com

<bind nodeset="/widgets/regex" type="string" required="true()"
 constraint="regex(., '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}')"
 jr:constraintMsg="this isn't a valid email address"/>

Repeat a group N times, where N is an answer to another prompt in the form

<!--  rare cases where the binding is defined in the body -->
<group>
  <label>repeat node a</label>
  <repeat nodeset="/data/repeat_node_a" jr:count="/data/repeat_count_a"
    jr:noAddRemove="true()">
    <input ref="/data/repeat_node_a/repeat_string_a">
      <label>this should repeat <output value="/data/repeat_count_a"/>
        times and finish</label>
    </input>
  </repeat>
</group>


You can add the binds below to your form for hidden or pre-loaded fields you want automatically filled in. You'll need a variable for them in the instance and a binding, but they have no body element and the user will never see or interact with them.

Form start time

<!--  stored the first time the form is loaded -->
<bind nodeset="/widgets/start_time" type="dateTime"
 jr:preload="timestamp"
 jr:preloadParams="start"/>

Form end time

<!--  updated every time the form is saved -->
<bind nodeset="/widgets/end_time" type="dateTime"
 jr:preload="timestamp"
 jr:preloadParams="end"/>

Current date

<bind nodeset="/widgets/date_today" type="date"
 jr:preload="date"
 jr:preloadParams="today"/>

Device ID (IMEI)

<bind nodeset="/widgets/deviceid" type="string"
 jr:preload="property"
 jr:preloadParams="deviceid"/>

Subscriber ID (IMSI)

<bind nodeset="/widgets/my_subscriberid" type="string"
 jr:preload="property"
 jr:preloadParams="subscriberid"/>

SIM serial number

<bind nodeset="/widgets/my_simid" type="string"
 jr:preload="property"
 jr:preloadParams="simserial"/>

Device phone number

<bind nodeset="/widgets/my_phonenumber" type="string"
 jr:preload="property"
 jr:preloadParams="phonenumber"/>