XLSXConverter - rev 116

The BETA-1 for ODK Survey is now available. This is a BETA release. It is not intended for production use.

This is an older version of our software.

The websites referenced in this documentation will generally have been updated to work with the newer software, and therefore may not function with this older release.

Where practical, we have provided zip files of the ApplicationDesigner environment used in creating those sites. See Survey and Tables Aux Files

Beta releases should never be used for production deployments. Beta releases are provided to gather bug reports (to make the application more robust) and for user feedback on the capabilities of the application. Updates may result in loss of data or incompatible changes in form designs.

We expect to release a second Beta with an incompatible database change as we align the database structures of ODK Survey, ODK Tables, and ODK Aggregate's new Tables storage subsystems.

Although, we consider this Beta to be nearly code complete, we are considering changes to how the back button works (both the device back button and the back button within the app). We also expect to change the CSS styling of the widgets to create a flatter, more modern, look-and-feel.

The purpose of this documentation is describe what the XLSXConverter is, how to load a converted form definition into ODK Survey on a tablet, and how to create xlsx workbooks that are compatible with the XLSXConverter. The document also covers more advanced topics like internationalization and customizing prompts.

Introduction

XLSXConverter is a part of ODK Survey. XLSXConverter is a tool similar to XLSForm that converts xlsx files into survey definition files that are used by ODK Survey. Forms created with XLSXConverter are not compatible with ODK Collect. They only work with ODK Survey.

For example, a spreadsheet like this:

type name display.text
begin screen
text name Enter name:
integer age Enter age:
end screen

Will result in a survey like this:

survey-screen

See the exampleForm.xlsx for a more comprehensive example.

Loading a Form into ODK Survey

  1. Use XLSXConverter to convert your xlsx workbook into json.
  2. Create the following directory structure: <formName>/forms/<formName>. For example, if exampleForm.xlsx is the name of the Excel workbook to convert, then exampleForm/forms/exampleForm would need to be created.
  3. Save the json output into a formDef.json file and place this file into the lowest level of the previously created directory structure (i.e. <tableName>/forms/<formName>). The form directory should also contain any necessary media/template/JavaScript files (their paths will be relative to the directory at the lowest level).
  4. Finally, place the top-level directory (<tableName>) inside your device's opendatakit/survey/tables folder. It should now be available in ODK Survey.

Getting Started with Survey Forms

ODK Survey offers a rich set of features that can be seamlessly integrated into a custom form.  A lot of the functionality can be implemented solely within an Excel workbook.  In order to take advantage of this tool, an understanding of the available components is necessary.

Overview of Excel Worksheets

A workbook is composed of one or more worksheets. XLSXConverter expects the worksheets within a workbook to use the following nomenclature.

Worksheet Required/Optional Description
survey Required Contains the content and control flow of the survey. It contains the full list of questions and determines the order in which they will be asked. This worksheet can be broken into different section worksheets for ease of use.
settings Required  Includes such details as the form name and id, as well as the default language.
calculates Optional Contains the JavaScript formulas that can be used in other worksheets
choices Optional Contains the sets of choices for multiple choice questions. Each row represents a response. Choices with the same choice_list_name are considered to be part of the same choice set. Choice sets can be used multiple times throughout a survey (such as a yes/no choice set).
model Optional Defines the table definition in cases where multiple forms edit the same data table
queries Optional Gets data from an external source that can be used as the choice set for mulitple choice or linked_table questions much like the choices worksheet.
user_defined_section Optional Worksheets with custom section names can be used in conjunction with the survey worksheet to simplify control flow.
prompt_types Optional Defines custom prompt types that can be used within a survey.
column_types Optional Defines custom column types that are formulas, functions, or pathnames.

Each worksheet has a set of required and optional columns. For the xlsx workbook to be valid, all entries must have legal values in the required columns. Optional columns can be left blank at any point, and omitted entirely if not used.

survey

All XLSConverter 2.0 form definitions require a survey sheet. The survey worksheet contains the structure and most of the content of the form. It contains the full list of questions and information about how those questions should be presented. Most rows represent a question; the rest of the rows specify control structures such as screen groups. Blank rows are ignored.

In this document, questions and question types will also be referred to as prompts and prompt types.  There are many prompts available for form development.  Some ask the user a question and get a response, but other prompts are simply informational and referring to them as questions is not semantically correct.

Required Columns

A list of the required columns for a survey worksheet follows.

Column Description
type The prompt type that will be used to display information to the user.  Prompt types can also be used to get data from a user.
name  The name of the prompt type.  This name will be used throughout the workbook to reference the prompt.
display.text The text that the user will see for this prompt type.

Optional Columns

A list of the optional columns that can be incorporated into a survey worksheet is below.

Column Description
branch_label Used to identify which part of the survey to branch to when used with a goto clause or user_branch prompt.
Calculation When used with the assign prompt type, assigns a value to a prompt type.
choice_filter Used to filter the choices of a multiple choice or linked_table prompt.
clause Used in conjunction with the condition column to manage the control flow of the survey. Clause and condition control which questions get asked in what order, if at all. The clause column contains control flow options such as if, and the condition column contains a predicate to determine if action will occur. if statements always require a condition statement. For other clause statements, a blank condition column is assumed to be true. Other commands include begin screen / end screen and do section.
comments Never displayed to the user. Used for development purposes to leave comments about the form for future reference. It is good style to comment your work.
condition Used with the clause column to manage the control flow of the survey. Clause and condition control which questions get asked in what order, if at all. The clause column contains control flow options such as if, and the condition column contains a predicate to determine if the following actions will occur.
constraint Takes a JavaScript expression. User cannot navigate forward until the constraint evaluates to true. If left blank, its default value is true.
constraint_message Message displayed to user if the constraint is violated. Tells the user what needs to change before he/she can continue.
default Used to set the default value.
display.audio Allows the user to play an audio recording. Requires a relative path to where the recording is saved. If saved in the same folder as the formDef.json, then only the filename of the recording needs to be specified.
display.hint Used to display text in italics and a smaller font than display.text. Can be used to provide extra instructions to the user.
display.image Used to display an image. Requires a relative path to where the image is saved. If saved in the same folder as the formDef.json, then only the image file name and the extension (for example .jpg, .gif) are needed.
display.title The display value the user sees when the prompt is displayed in the contents screen.
display.video Allows the user play a video. Requires a relative path to where the video is saved. If saved in the same folder as the formDef.json, then only the filename of the video needs to be specified.
hideInContents Legal value is true.  If true, then the prompt on the same row will not be displayed on the contents screen.
inputAttributes.<attr> This column can be used in conjunction with the following prompt types: string, text, integer, decimal.  The <attr> can specify an html attribute to be added to the prompt types.  For example, inputAttributes.min with a value of 5 would add min=”5” into the html element for the prompt type.
model.isSessionVariable Legal value is true.  If true, then the data value for the prompt will be treated as a session variable and won't be saved.
required Takes a JavaScript expression. If true, the user will not be able to navigate to the next screen until the question is answered. If left blank, its default value is false.
templatePath Must be specified if using a custom handlebars template. Requires a relative path to where the template is saved. If saved in the same folder as the formDef.json, then only the filename of the template needs to be specified.
values_list Must be used with the choices worksheet.  The value_list column of the survey worksheet connects to the choice_list_name column on the choices worksheet.

Prompt Types

The following prompt types are available in ODK Survey.

Prompt Type Description
acknowledge Used to display a message to the user and have them click a checkbox to acknowledge that they have read the message.
assign Used for internal assignment of a variable.
audio Used to capture an audio recording.
barcode Used to capture a barcode.
date Uses a date picker widget to capture a date.
datetime Uses a date time picker widget to capture a date and time.
decimal Used to display a message to the user and have them enter a decimal.
geopoint Used to capture a GPS location.
image Used to capture an image.
integer Used to display a message to the user and have them enter an integer
linked_table Used to display the instances of table and allows the user to add another instance, edit an existing instance, or delete an instance.
note Used to display a message to the user.
select_multiple Used to ask the user a multiple choice question and allows the user to click multiple checkboxes.
select_multiple_grid Used to ask the user a multiple choice question, displays the choices to the user in a grid, and allows the user to click multiple grid items.
select_multiple_inline Used to ask the user a multiple choice question, displays the choices to the user inline, and allows the user to click multiple items.
select_one Used to ask the user a multiple choice question and allows the user to click one item.
select_one_dropdown Used to ask the user a multiple choice question and allows the user to select one item from a dropdown box.
select_one_grid Used to ask the user a multiple choice question and allows the user to select one item from a grid.
select_one_inline Used to ask the user a multiple choice question, displays the choices to the users inline, and allows the user to click one item.
select_one_with_other Used to ask the user a multiple choice question, displays the choices to the user, and allows the user to click one item. One of the choices provided is an other option which if clicked provides a text box for the user to enter a value.
string Used to ask the user a question and allows them to enter a string.
text Used to ask the user a question and allows them to enter text.
time Uses a time picker widget to capture a time.
user_branch Used to allow the user to pick which section of the form they would like to enter.
video Used to capture a video.

settings

Column Description
setting_name The name of the setting within the form
value The value for the setting
display.title The text shown to the user when the setting is displayed.

Available settings that can be used

  • form_id – A unique identifier for the form
  • form_version – A value used for version control of the form.  The recommended format is yearmonthday (i.e. 20131212).
  • table_id – The id of the table that form data gets stored in
  • display.title – The text that the user will see when the setting value is displayed to the user.
  • default – Used with display.text to set the default language used in the form.
  • instance_name - Used to display the name of saved instances of the form.  This must be the name of a prompt type from the survey worksheet.
  • <language> - Used with display.text.<language> to set other language options in the form
  • <section_name> - Used with display.text to set how the section name will appear to the user on the contents screen.

A sample settings worksheet might look like this:

setting_name Value display.title display.text  display.text.hindi
form_id sample_form
form_version 20130819
survey  Sample Form
default English  English (as hindi name)
hindi Hindi  Hindi( as hindi name)

The only rows that are required are form_id and survey. form_id is the unique id that ODK Survey uses to identify the form. form_version is used for version control if you made a small change to the form and want to keep the same form_id. The recommended form_version is a date in the form of yearmonthday as shown above. In the next row, the display.title for survey is set to Sample Form. This is what the user will see as the title for the survey. If the survey has been broken up into multiple worksheets, each worksheet can be assigned its own title by adding a row for it and filling in the display.title column. In the case of multiple languages, the display.text column determines how the different language options are presented to the user.

choices

The choices sheet allows you to specify the set of choices for multiple choice prompts.

The value_list column of the survey worksheet connects to the choice_list_name column on the choices worksheet. The data_value column contains the actual value that will be used if the choice is selected. The display.text column is what the user sees as the choices. The data_value and display.text columns of the choices worksheet are analogous to the name and display.text columns of the survey worksheet.

Column Description
choice_list_name The name used to reference the set of choices.  This name must be the same as the values_list in the survey worksheet.
data_value The value that gets stored as the user’s response.
display.text The text that the user sees when selecting a choice.
display.image An image that the user will see associated with a particular choice.

calculates

The calculates worksheet is an optional worksheet. It consists of two columns: calculation_name and calculation. Each row of the calculates page represents a function that can be used elsewhere in the workbook by referencing the individual calculation_name. The calculation column can store any valid JavaScript expression. There are also some built in functions for ODK Survey that can be used anywhere in the workbook. See the Formula Functions section for more details.  In general, calculations are referenced in the condition column of survey worksheets.

Column Description
Calculation_name The name used to reference the calculation in other worksheets.
calculation The JavaScript formula to be evaluated.

queries

The queries worksheet is an optional sheet that allows you to request data from external sources for use in select prompts. These are some of the things you can do with queries:

  • Connect to website APIs.
  • Get data from external Android Applications via file content providers.
  • Get data from a linked table
  • Open csv files included in the survey's directory.
Column Description
query_name The name used to reference the information returned by the query.
query_type Legal value are ajax, csv, and linked_table.  Used to specify the provenance of the query data.
uri Used by ajax and csv queries.  The uri to use for an ajax query or the name of the csv file to use relative to the location of the formDef.json file.
callback Used by ajax and csv queries.  The function that will be used to map the query results to the set of choices for a multiple choice prompt.
linked_table_id Used by linked_table queries.  The table_id used to identify the table that the data will come from.  This should match the table_id provided in the settings worksheet.
linked_form_id Used by linked_table queries.  The id of the form that will be used to get the results for the linked_table.  This value should match the form_id value in the settings worksheet.
selection Used by linked_table queries to filter results when used with selectionArgs.  Specifies the conditions that must be true for the results to be selected but must have selectionArgs to work.
selectionArgs Used by linked_table queries to filter results when used with selection.  The arguments to be used in the selection described above.
orderBy Used by linked_table queries to specify the order in which results should be returned.
auxillaryHash Used by linked_table queries.  An ampersand separated list of key value pairs used to assign initial values.  The key is the element name in the form.  The value is the initial value to assign to the element.

model

The model sheet is an optional sheet that allows you to specify the data model for the table_id specified in the settings worksheet.

Column Description
name The name of the data field to be used in table_id
type The type of data that can be put into this data_field of the table.

user_defined_section

A custom named section is essentially a subset of the survey worksheet.  Thus, all of the columns that were described in the survey section are applicable in a custom section worksheet. However, the following worksheet names are reserved and cannot be used to name a custom section worksheet:

  • settings
  • choices
  • queries
  • calculates
  • column_types
  • prompt_types
  • model

prompt_types

Custom prompts can be created within the survey.  The prompt_types worksheet can be used to specify the custom prompts so that they will be recognized by Survey.

Column Description
prompt_type_name The name that will be used to reference the prompt_type
type The type of object that will be used to store the data received by the user for this prompt type.

column_types

Custom columns can be used within a workbook that are used to store functions, formulas, and path names. The column_types worksheet can be used to specify these custom columns.

Column Description
column_type_name The name that will be used to reference the column.
type The type of information that will be stored in the column (i.e. function, formula, app_path_localized).

Built-in Functionality

ODK Survey provides built-in functionality through formula functions to decrease form development time.

Formula Functions

The following formula functions can be used to simplify calculations or expressions.

Name Description Example
countSelected Returns the number of items selected from a select_multiple prompt countSelected(data(‘options’))
data Returns the data of a prompt data(‘options’)
equivalent Check to see if two values are equivalent equivalent(data(‘option1’), data(‘option2’))
localize Localizes the text passed in.  localize(data('options'))
not Negates the argument passed in. not(selected(data('examples'), 'label_features'))
now Returns the current date now().getDay()
selected Returns true if the value selected from a select_ prompt is equal to the second argument passed into the function. selected(data('visited_continents'), 'NorthAmerica')

Putting It All Together

After understanding all of the components available, using the worksheets to create custom survey should be fairly straightforward.

Creating a Simple Survey Form

Typing the following in the survey worksheet of a workbook with an appropriate settings worksheet will result in a simple survey.

clause Condition type name display.text
integer person_age How old are you?
if data('person_age') >= 18
begin screen
text pizza_type What is your favorite kind of pizza?
integer num_slices How many slices would you like?
end screen
else
note You are too young to be eating pizza
end if

The first row contains an empty clause and an empty condition column. Therefore, the display.text will be shown on the screen, and the resulting integer answer will be stored in the variable person_age. On the next line there is an if in the clause column and data('person_age') >= 18 in the condition column. If the answer stored in the variable person_age is greater than or equal to 18, the following commands should be done until either an else or an end if tag is reached. Notice the other three columns are left blank. In the next row, there is a begin screen tag in the clause column. The remaining four columns are left blank. Until an end screen tag is reached in the clause column, all the following questions will be displayed on one screen. In this case, the user will be asked to input their favorite type of pizza and how many slices they would like on the same page, assuming they are 18 or older. In the next row, there is an else tag. Until end if is reached, anyone who did not satisfy the requirement for the if tag will be asked the following questions. In this case, a note to the user that they are too young to be eating pizza will be displayed.

An important thing to remember when using the clause column is when to open and close new tags. The general rule is that the most recently opened grouping is the first to be closed.

Adding Multiple Choice Questions

There are three types of multiple choice questions supported by ODK Survey: select_one, select_one_with_other and select_multiple. Multiple choice questions use the values_list column in the survey worksheet. The values_list column is what links a multiple choice question to its answer set contained on the choices worksheet.

The pizza survey example used earlier can be improved upon with multiple choice options.

The resulting survey worksheet would look like this:

clause Condition type values_list name display.text
select_one  yes_no person_age Are you 18 or older?
if selected(data('person_age'), 'yes')
begin screen
select_multiple topping_list pizza_type What are your favorite kind of pizza toppings (select up to 3)?
integer num_slices How many slices would you like?
end screen
else
note You are too young to be eating pizza
end if

and the corresponding choices worksheet would look like this:

choice_list_name data_value display.text 
yes_no yes Yes
yes_no no No
topping_list pepperoni Pepperoni
topping_list olives Black Olives
topping_list onions Onions
topping_list mushrooms Mushrooms
topping_list peppers Green Peppers
topping_list bacon Canadian Bacon
topping_list pineapple Pineapple

Now, instead of typing their age, the user simply selects whether they are older than 18 or not. Furthermore, instead of entering the type of pizza they like, they can select from a list of toppings.

Because you determine whether a question is select_one or select_multiple from the survey worksheet, the same choice set on the choices worksheet can be used for both select_one and select_multiple questions.

Using Custom Section Worksheets

Custom section worksheets can be added to a workbook to make the control flow of a survey more readable. We could move all the previous questions about pizza to a new worksheet and name it Pizza. Our survey worksheet would then look like this:

clause condition type values_list name display.text
do section Pizza

When splitting a survey into different sections, it is wise to put a note before each section call with display.text set to "Section <name_of_section>". This is because a do section <name_of_section> call is transparent to the user. Unless the form designer explicitly adds a note, the user will not realize that they entered a section. Also, after leaving a section, if the user swipes back, the survey will go to the row before the do section call. If the user then swipes forward at this point, the survey will go to the beginning of the section they just completed. It is often beneficial to the user to put a note before entering a section and before leaving a section.

Using Calculations

The calculates worksheet is an optional worksheet. It consists of two columns: calculation_name and calculation. Each row of the calculates page represents a function that can be used elsewhere in the workbook by referencing the individual calculation_name. The calculation column can store any valid JavaScript expression. There are also some built in functions for ODK Survey that can be used anywhere in the workbook. See the Formula Functions section for more details.  In general, calculations are referenced in the condition column of survey worksheets. For example, suppose that on the survey page under the variable name birthday the user entered their birthday for a question of type date. The calculates worksheet might look like this:

calculation_name Calculation
daysOld (now().getTime()-new Date(data('birthday')).getTime())/1000/60/60/24
isBirthdayToday calculates.daysOld()%365 == (now().getTime()/1000/60/60/24)%365

and one of the survey worksheets may look like this:

clause condition type name display.text
if calculates.isBirthdayToday()
note happyBirthday Happy Birthday!
end if

Notice that the <calculation_name>s do not contain () at the end of them. However, when referencing them it is always in the format of calculates.<calculation_name>(). This example also serves as a good reminder that variable names have scope for the entire workbook.

The calculates worksheet is handy because it adds readability to a workbook. Instead of having long, complicated JavaScript calculations in the survey worksheets, they can be consolidated in one, easy to reference location that allows for reusability. Also notice the consistent use of camelCase for variable naming across the different worksheets.

Using Queries

The queries worksheet is an optional worksheet. For queries that get their data from external sources, the following columns should be used: query_name, query_type, uri, and callback. For linked_table queries, these columns should be used: query_name, query_type, linked_table_id, linked_form_id, selection, selectionArgs, orderBy, and auxillaryHash. Each row of the queries page represents a choice set that can be used by select prompt types in the workbook. In general, query_name is referenced in the values_list column of survey worksheets. For example, suppose that on the survey page under the variable name region the user is asked to select the region they are from. Then the user is asked to select which country they are from. The choices for the list of countries can be filtered based on the region the user selected. The queries worksheet might look like this:

query_name query_type uri callback
regions_csv csv "regions.csv" _.chain(context).pluck('region').uniq().map(function(region){
return {data_value:region, display:{text:region}};
}).value()
countries_csv csv "regions.csv" _.map(context, function(place){place.data_value = place.country;
place.display = {text:place.country};
return place;
})

The data for the queries is coming from the regions.csv file that is located in the same directory as the formDef.json and specified in the uri column. Thus, the query_type for both queries is csv. A snippet of the regions.csv file looks like the following:

region,country
Africa,Algeria
Africa,Angola
Africa,Benin

Knowing the structure of the regions.csv helps in understanding the callback function provided in the callback column.  The callback function maps the results from the regions.csv file to the data_value and the display.text fields using JavaScript.  The survey worksheets may look like this:

clause condition type values_list name display.text choice_filter
begin screen
select_one_dropdown regions_csv region Please select your region:
select_one_dropdown countries_csv country Please select your country: choice_item.region === data('region')
end screen

The choice_filter in this example ensures that the options for the country question will only be the countries from the previously selected region. Notice that choice_item.region specifies that any country with a corresponding region equal to the answer stored by the region question will be displayed.  

The queries worksheet is powerful because it allows more flexibility in terms of where data for the survey can reside.  

linked_table is the other use for the queries worksheet. linked_table allows you to launch a subform that can edit a different data table. For example, if a survey is dealing with information about households, the user may want to ask questions about the general household but also questions about specific users. linked_table can be used to launch subforms that ask questions about the specific household members. The survey worksheet may look like this:

clause condition type values_list name display.text choice_filter
 text house_id Input the unique household id:
integer num_members How many people live in this house?
linked_table members Add and enter information for the different household members
select_one members household_head Who is the household head?

The queries worksheet would look like this:

 query_name query_type linked_form_id linked_table_id selection selectionArgs auxillaryHash
 members linked_table members_info house_members house_id = ? [ data('house_id') ] ''house_id='+escape(data('house_id'))

First the user enters a house id for the house and answers an arbitrary question about its residents. This information is stored in the data table for general household information (specified on the settings worksheet under table_id). Then the user reaches a linked_table prompt that uses the values_list members. This is connected to the members query on the queries worksheet. It links to a different survey called members_info that edits a different data table. The selection criteria is that the house_id in the house_members data table matches the house_id for this current household. Initially this list will be empty since no members have been added. The user can click on the create instance button to add new people for this household. The house_id will be set automatically for this new member by the auxillaryHash function. When the user finishes the subform, the screen will return to the same linked_table prompt. At this point, the user can continue adding more users, edit an existing member's info, or go to a different screen.

The values_list for the select_one question prompt in the example above also uses the members query. Instead of being able to launch subforms to edit information about different members, the selection criteria is used to populate a multiple choice question. The answer to the multiple choice question is saved to the general household data table, not the members data table.

Internationalization

Survey offers the ability to display text in different languages. This requires usage of the settings worksheet to determine which language to use. However, for any language other than the default language, extra display columns need to be added. For example, if one of the non-default language options was Spanish, every worksheet with a display.text column would also need a display.text.spanish column. This is true for all columns that need an alternate language option.

type name display.text display.text.spanish
text user_name What is your name? ¿Cuál es su nombre?
integer user_age How old are you? ¿Cuántos años tienes?

More Advanced Branching

ODK Survey supports situations where the user needs to be in control of which survey or section of a survey they are working on. To do this, the branch_label column is used, as well as the choices worksheet. It also utilizes a new question type: user_branch. The following example combines aforementioned surveys and allows the user to decide whether they want to fill out the survey about pizza, or the survey about birthdays.

A choice set needs to be added to the choices worksheet with the applicable branching options. The resulting choices worksheet would look like this:

choice_list_name data_value display.text
 which_form  pizza_form Order pizza?
 which_form  birthday_form  Is it your birthday?

And the survey page would look like this:

branch_label clause condition type values_list display.text
user_branch which_form Choose a survey to fill out
 pizza_form
 do section pizza
 birthday_form
 do section birthday

The xlsx file would then have corresponding section worksheets called pizza and birthday that contain the survey examples documented earlier.

Creating a Custom Initial Worksheet

When ODK Survey opens, it displays a list of the different forms available on the device. After the user has selected which type of form to work on, Survey launches the initial worksheet for that particular survey. So far the initial worksheet has not been discussed and if one is not explicitly included in the xlsx file, survey uses this default initial worksheet:

clause Condition type display.text
 if // start  (opendatakit.getCurrentInstanceId() != null)
opening Edit form
 do section survey
 finalize Save form
 else // start
 instances  Saved instances
 end if // start

This checks to see if an instance of the current form has been selected (opendatakit.getCurrentInstanceId() != null). If it has, it opens that form. If not, it displays the instances that the user can edit. This utilizes three new types: opening, finalize, instances. When creating a custom initial worksheet, it is very important to include a finalize type. After completing a survey, it is the finalize prompt that lets the user formally finish the survey so that the results can be used.

Using Validate

When users start having more control over which questions they are asked, it can lead to problems if they bypass required prompts. The validate feature allows for the form creator to require form validation in custom places. By default, the form performs a validation during the finalize section of the survey. However, this type of operation can be performed at multiple points throughout the survey on specific questions using the prompt type validate and the column validation_tags. The following example will collect information from a user in section1 and section2 and will prevent completion of section3 if certain questions have invalid answers.

The survey page would look like this:

branch_label Clause type values_list display.text
 welcome_screen
 user_branch  which_branch  Choose the section to enter
goto welcome_screen
 branch1
note Selected Section 1
 do section section1
note Returning from Section 1
 goto welcome_screen
 branch2
 note Selected Section 2
 do section section2
note  Returning from Section 2
 goto welcome_screen
 branch3
Note Selected Section 3
 validate user_info
 do section section3
Note  Returning from Section 3
goto welcome_screen

The choices worksheet would look like this:

choice_list_name data_value display.text
 which_branch branch1  Do Section 1
 which_branch  branch2  Do Section 2
 which_branch  branch3  Do Section 3

The section1 worksheet would look like this:

 type name display.text required validation_tags
 text user_name What is your name? TRUE user_info, finalize
 integer user_age What is your age?  TRUE user_info, finalize
 note Thank you for answering

The section2 worksheet would look like this:

 type name display.text required validation_tags
 text occupation What is your current occupation? TRUE user_info, finalize
 integer user_age How long have you worked at your current job (in years)?  TRUE finalize
 note Thank you for answering

If the user selects to do section 3 on the welcome page, survey will jump to the branch3 branch_label. The first row says to validate user_info. Survey then checks that every question with the validation_tags user_info has been answered satisfactorily. If the questions have been answered correctly, it will go on to the next line (do section section3). If not, it will force the user to answer the missing, tagged questions.

The use of many different validation_tags can allow users to update information in the survey as it becomes available and to restrict questions that depend on other information. In general, the validation feature can be used to give users more control over their work while still maintaining a level of order and restriction.

Like the use of sections and gotos, validate has no user interface. In other words, when a user runs into a validate call, they will have no idea unless Survey finds something wrong with the form. Whenever using sections, gotos, or validates, if the form designer wants the user to be aware of what is happening, a note explicitly informing the user must be added.

Customizing Prompts

There are 3 ways to customize prompts:

  1. Add additional columns to your XLSConverter 2.0 form definitions like inputAttributes to tweak existing prompts.
  2. If that's too limiting, you can make a custom HTML template by setting the templatePath column. Templates can include <script> and<style> tags.  ODK Survey uses handlebars templates. Handlebars has a few built-in helpers for creating conditional templates and templates with repeated components.
  3. Finally, if you need to parse data from a special type of input or retain some kind of state while your widget is active, you will need to delve into the ODK Survey 2.0 JavaScript. By providing a customPromptTypes.js file in your form directory, you can define Backbone views that extend the base prompts.

To change a form's css styles include a customTheme.css or customStyles.css file inside the directory where the formDef.json resides. customTheme.css is intended to be a jQuery Mobile theme generated by the jQuery Mobile ThemeRoller that changes the form's overall appearance. customStyles.css is intended for adding individual css rules.

Future Features

Different surveys and forms can also be entered using the external_link type, the url column, and the url.cell_type column. Currently, this feature only works when using ODK Survey on Google Chrome, eventually it will work on the android version of Survey as well. To access a separate survey stored elsewhere, a local url can be specified in the format: '?' + opendatakit.getHashString('<relative path to survey>', null). Converting the example above to this format would leave the choices worksheet looking the same. However, the survey worksheet would look as follows:

branch_label clause condition type values_list display.text url url.cell_type
user_branch which_form Choose a survey to fill out
pizza_form
 external_link  Open Form  '?' + opendatakit.getHashString('../tables/pizza/forms/pizza/', null) formula
 exit section
birthday_form
external_link  Open Form  '?' + opendatakit.getHashString('../tables/birthdays/forms/birthday/', null) formula
exit section