ODK2 Documentation
ODK2 Documentation
1 Learn More 3
2 Perspectives 5
3 List of Tools 7
4 Trying It Out 9
The ODK-X Tool Suite is a new set of ODK tools that will co-exist with the existing ODK
Tool Suite. It targets advanced users who find themselves limited by the ODK data collection
workflows. It provides:
• Fully customizable layout of prompts on the Android device. The ODK-X
tools use HTML, JavaScript, and CSS to specify the layout of nearly all the screens
viewed by the data collectors. This enables individuals and organizations with basic
web development skills to modify and customize the appearance of their surveys and
workflow. At the same time, we retain the easy-to-use spreadsheet-based definition of
the survey questions (however, this XLSX Converter mechanism is not cross-compatible
with XLSForm).
• More flexible, user-directed, navigation of a survey. The ODK-X tools do
not impose a strict sequential advancement through a form like ODK Collect. Form
designers can allow users to traverse a form in any order, yet impose validation of
collected data prior to traversing into subsequent steps in a workflow.
• Improved treatment of repeat-groups. In the ODK-X tools, we have eliminated
the concept of a repeat-group. In its place, we provide prompts that enable you to open
and edit other surveys with links back to the originating survey (if desired). These
prompts can describe a sub-form (nested) relationship among the surveys (for example:
household and household-member) or they can represent arbitrary relational linkages
across your data (for example: tea-houses and tea-types).
• Bi-directional synchronization of data across devices. The ODK-X tools sup-
port the collaborative sharing of survey data across devices, as well as the updating
and submission of changes to previously collected data (for example: follow-up surveys)
via a bi-directional synchronization protocol. This contrasts with the unidirectional
device-to-server submission pathway of ODK Collect / ODK Aggregate / ODK Brief-
case.
• Data curation and visualization on the device. ODK Tables gives organizations
the ability to investigate and visualize entire datasets directly on the Android devices
through graphical and non-graphical displays and through filtered views.
• Row-level access filters. The visibility of the data and the ability to edit and/or
delete data can be restricted for different users and groups.
Note: The ODK-X tool suite is targeted at advanced users who are unable to complete
their workflows with the ODK tools. If you find that the ODK tools meet your needs then
there is no reason to switch.
ODK-X is a platform that will run your data management applications. With ODK you
create survey forms that ODK Collect renders and are used to collect data and submit it
to the ODK Aggregate server. In ODK-X, you create data management applications that
consist of survey forms (similar to those used in Collect) as well as Javascript based web
apps that allow you to render a fully customized user interface and implement business logic
in order to collect, manage, and visualize data all on the Android device.
ONE
LEARN MORE
View a brief feature comparison in the guide for Selecting the Appropriate Tool Suite.
TWO
PERSPECTIVES
The ODK-X documentation is organized into different perspectives to allow readers to focus
on the sections most relevant to their needs.
These perspectives are:
• User: A user of the data management application running on the Android tools. This
person collects and interacts with data on the Android device. Examples include field
workers, clinic staff, and census workers.
• Deployment Architect: An author of a data management application or a consumer of
collected data. This person might create forms and edit Javascript on their computer
to deploy to the Android device. Or they might download data from the server and use
Excel to perform analysis. Examples include technical staff and data analytics staff.
• System Administrator: The person or team that manages the web servers in the cloud.
This person might want to ensure high availability of the server or coordinate across
multiple regions.
• Platform Developer: A programmer that intends to modify the source code of the
ODK-X tools themselves. This person might want to add a new view type or a fix a
bug.
Note: We expect most organizations to have users, deployment architects, and system
administrators (though these roles might overlap). But most organizations can safely ignore
the platform developer sections.
THREE
LIST OF TOOLS
Tip: The tools operate independently – you are not required to use all the tools, or even
install them on your device. If you are only interested in data collection, you may only want
ODK Survey. Or if you are only interested in data dissemination and visualization, you
might only want ODK Tables.
Simply select the combination or individual tool that fits your needs. However, all of these
tools require ODK Services to access the database, sync to a server, and vend HTML files.
FOUR
TRYING IT OUT
The first step to get a feel for the ODK-X tools and how they fit together is to do the Getting
Started User Guide. This guide walks you through the process of using a basic geotagging
application and submitting data to the server. After this is completed, the guide provides a
list of Next Steps for the user.
Deployment Architects should follow this up with the Getting Started Deployment Architect
Guide to get an introduction into revising and editing their own forms. That guide walks
you through modifying the Geotagger demo application to add a new field to it. Similar
to the user guide, this guide provides a list of Useful Grunt Commands for the Deployment
Architect.
System Administrators should learn about ODK Cloud Endpoints.
Platform Developers should already be familiar with everything from the User and Deploy-
ment Architect sections, and can learn more in the Platform Developer Advanced Topics
documentation.
Generally, we suggest starting with the ODK tool suite. If it does not fulfill your requirements
then move on to the more flexible, but also more complex, ODK-X tool suite.
Note: It is tempting to look at the version number and assume the latest is the greatest,
but this is not always the case. The ODK-X tool suite was designed to co-exist with the
ODK tool suite and does not replace any 1.x tools. In general, the ODK tools are easier to
use, require less setup, and are widely adopted. However, if you have a complex longitudinal
study and possess some technical skills, then the ODK-X tools may be better suited to your
needs.
The feature comparison table below illustrates the differences between the ODK and ODK-X
tools.
Maturity Introductory
Stage of technology lifecycle
x x
Collect data with mobile
device
x
Widely adopted
x
Drag and drop tool to
create forms
x x
Transmit collected data
from device to server
x x
Ability to capture rich data
types (e.g. GPS, Images,
Audio, Video)
x x
One to one mapping of a
question to database fields
(except for GPS)
x
One to many mapping of a
question to database fields
x x
Static input contraint
checks
10 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
x
Dynamic input contraint
4.2. Getting Started User Guide
• Try the 1.x tools with the Getting Started With ODK guide.
• Try the 2.x tools with the Getting Started User Guide.
A major goal of these ODK-X tools was to eliminate the need for any software engineering
skills (for example: Java programming, Android software development environment, source
code version control systems) when designing data management applications. The skills
required to build a data management application range from scripting a form definition
in XLSX (similar to constructing ODK Collect forms using XLSX files processed by the
XLSForm tool), to simple web programming – modifying boilerplate HTML and JavaScript
for custom presentations of the collected data. Advanced web programmers can also easily
implement entirely custom web pages.
The ODK-X tools are intended to address limitations of the existing tool set. The ODK-X
Tool Suite consists of:
• ODK Survey - a data collection application based upon HTML, CSS, and JavaScript.
• ODK Tables - a data collection and visualization application running on your device.
• ODK Services - an application that handles database access, file access, and data
synchronization services between all of the ODK 2 applications. It also allows you
to synchronize data collected by the ODK 2 tools using the 2 protocol with an ODK
Aggregate instance.
• ODK Application Designer - a design environment for creating, customizing, and pre-
viewing your forms.
• ODK Cloud Endpoints - a ready-to-deploy server and data repository with enhance-
ments to support bi-directional data synchronization across disconnected devices.
• ODK Suitcase - a desktop tool for synchronizing data from an ODK-X server so the
data can be exported to CSV format.
This page provides a brief end-to-end walk-through of the ODK-X tools. It will cover the
following topics:
– Checkpoint Resolution
– Conflict Resolution
• Next Steps
The ODK-X Android tools (ODK Survey, ODK Tables, ODK Services, ODK Scan, ODK
Sensors Framework, and various ODK Sensor implementations) are Android Application
Packages (APKs) that are designed to work together to create a coherent tailored application
experience for an end-user.
Note: Together the ODK-X tools create a platform, on top of which you can build your
own data management applications.
ODK-X tools access configuration files and store data under sub-directories of the
opendatakit directory in the sdcard root directory (whether your device has a physical
SD card or not): /sdcard/opendatakit. User applications constructed using the ODK-X
tools are identified by the name of the sub-directory holding those configuration and data
files. Thus, /sdcard/opendatakit/mytestapp would contain all the files and data for the
mytestapp application, where mytestapp, is the AppName of that application. The de-
fault AppName for the ODK tools is default. However, when configured appropriately, the
ODK tools can run under another AppName, accessing configuration and saving data in a
different subdirectory under opendatakit.
This is handled in such a way that each user application is isolated from all other user
applications, with separate configurations, data tables, and server settings. This allows
one device to run multiple user applications built on top of the ODK-X tools without any
coordination among the teams developing those applications.
We will use a Server called Aggregate to get the data for a demo application that we will
walk through.
The steps for joining a device to an existing Aggregate server are straightforward.
1. Install the APKs your application uses.
2. Launch the home screen APK, either ODK Survey or ODK Tables.
3. Click on the circular arrows button to launch the ODK Services sync activity in the
context of your home screen APK.
4. Configure ODK Services to point to the ODK Aggregate instance you want to join.
5. Choose Sync now to make the device mirror the contents on that ODK Aggregate
server.
Follow the steps described above to join the ODK Aggregate server hosting our simple demo,
which uses ODK Tables as its home_screen APK. The detailed steps are:
1. Download and install ODK Services, ODK Tables, and ODK Survey.
2. Launch ODK Tables (the home_screen APK).
3. Click on the circular arrows button to launch the ODK Services.
4. The default Sync Configuration should be https://open-data-kit.appspot.com and None
(anonymous access). You will need to change that. It will also default to Fully Sync
Attachments.
5. Click on the gear - shaped button in the menu bar, then select Server Settings in the
pop-up screen.
6. Click on Server URL and replace the default server with https://opendatakit-
simpledemo.appspot.com then click OK.
7. Back out of settings then choose Sync Now.
The synchronization process will now occur.
Note: If there is an error, check to make sure the server URL is correct, then choose Sync
Now again until it completes successfully.
Once successful, back out of ODK Services, returning to ODK Tables. And back out of ODK
Tables. Then relaunch ODK Tables.
You should now see the custom home screen for the Geotagger demo:
This demo is based upon the geotagger data table and form. It allows users to record the
date, time, GPS coordinates, description, and picture of their current location.
When you launch the demo by clicking the blue launch button, you see a map showing
the collected data points, indicated with markers. By clicking on a marker, you bring its
data record to the top of the list of records above the map. Clicking on the record header
will expand or contract that item to show the coordinates and photo of that location. For
example, if we click on the Phinney Ridge marker, its color changes from blue to green, and,
if we then touch the Phinney Ridge heading, it expands to show the coordinates and image
of that location:
You can add a new data record by choosing the + icon in top menu bar. This opens ODK
Survey.
Note: Since ODK Survey is being opened for the first time, it will initialize itself. This
may take a few moments.
Advance through and finalize this form. Upon finalizing the form, you will be returned to
ODK Tables and its map view. You can then highlight the marker you added and view the
image in the list view:
If you then click or tap in the list item details area (on the image), a detail view of the item
will be displayed.
From here, if you were to choose the pencil icon, ODK Survey would be launched to edit
this record.
You can also view the data in a list view or spreadsheet view by choosing the sheet icon in
the menu bar and selecting the view you want:
Tip: These other views can be useful if you need to access and complete data records that
do not yet have location data and cannot therefore be displayed on a map. Try these other
views now.
Now back out of the geotagger table view and return to the custom home screen. Choose
the three-horizontal-line icon on the top menu bar and choose Sync. This opens up ODK
Services in its sync activity. Sync your device with the server (choose Sync Noaw). This
will push your newly added record to the server. You can see this by browsing to https:
//opendatakit-simpledemo.appspot.com click on the ODK Tables tab, choose the View Table
sub-tab, and select the geotagger table.
If you then repeat these steps with a different device, you can see that the two devices can
share and exchange data, and revisions to this data, whenever they synchronize to the server.
Note: During this process, there are two problem-resolution screens you are likely to
encounter:
• Checkpoint Resolution - if ODK Survey exits without the user explicitly saving their
additions or changes.
• Conflict Resolution - if ODK Services detects a change on the server to a data record
that was also changed on the device.
Checkpoint Resolution
The checkpoint resolution screen can be triggered a variety of ways. For this tour, choose
the + icon then back out of ODK Survey:
In all of these screens, you can choose whether to save the changes as incomplete or to discard
them.
Conflict Resolution
The conflict resolution screen is triggered when another device has edited one or more rows
and synchronized its changes to the server before your edits to those same rows have been
synchronized. In this case, your synchronization attempt will end with an error, and a
Conflicts Detected error will appear:
Once you click OK, the conflict resolution screen will be presented. If there are multiple
rows in conflict, this screen will display the rows that are in conflict:
And if only a single row is in conflict, the list-of-rows screen will be bypassed.
The conflict details screen displays the values of the field(s) in conflict, with the field value
on the device (Local) appearing first. In this case, the Description field is in conflict. The
device has Kite hill at Gasworks and the server has Kite Hill … Gasworks. You can select
either to take your device values (Take Local Version) or take the server’s values (Take
Server Version) or pick-and-choose among the changes and merge them (the Merge Changes
as Indicated Below button will be enabled after all fields have had either their Local or Server
value picked for the merge). After selecting the local version or choosing to merge, you must
again synchronize with the server to push that change up to the server.
Warning: When you resolve a conflict, your decision does not only affect you. The
value you choose becomes the new true value and the next time you sync it will be written
to the server.
This concludes the tour of the Geotagger example application’s screens, and the functionality
within ODK Tables. For larger tours of sample applications, try the ODK Survey: Sample
Application and ODK Tables: Sample Application.
Users can browse the user guides for the Android tools. Tables and Survey’s documentation
each guide you through the use of sample application to better familiarize with the workflow
of each tool.
• ODK Survey
• ODK Tables
• ODK Services
Development Architects should continue this tour in the Getting Started Deployment Archi-
tect Guide.
• Prerequisites
• Migrating / Setting-up an ODK-X application
– Setting up the ODK Aggregate server
– Resetting the Application on the Server
• Configuring your Device with an Application
– Setting up ODK Application Designer
– Deploying to the Device
– Resetting the Server
• Modifying an ODK-X application
– Modifying the data entry form
– Updating the Initialization Files
– Updating the Preloaded Data
– Updating the HTML files
• Useful Grunt Commands
• Next Steps
4.3.1 Prerequisites
This guide continues the tour were Getting Started User Guide left off. If you
haven’t yet completed that tour, do it first. When you have concluded the tour
of the Geotagger example application’s screens, return to this guide and we will
turn to setting up our own ODK Aggregate server, and setting the application
up to run on that server.
Now that we have seen how a device can join an already-configured application, and syn-
chronize its view of the data with the ODK Aggregate server hosting the application, it is
time to set up our own ODK Aggregate server.
The starting point for this is to have a fully configured application on your device. Only
proceed with the following steps after you have your device configured as you want it to
appear. In this case, we already have the device configured with the Geotagger demo, so
let’s proceed to create an ODK Aggregate server and configure it to serve that demo to your
devices.
Follow the instructions for Installing Aggregate. You must install the ODK Aggregate
v1.4.15 release. This is because we are transitioning away from Aggregate and towards
ODK Sync Endpoint, but v1.4.15 will suit the purposes of this demo fine.
Once you have installed ODK Aggregate, log in with your super-user account. That process
is also covered in Installing Aggregate.
Once logged in, enable the ODK Aggregate Tables Extension. You should grant the user
account on your device the Administer Tables permissions.
Resetting the application on the ODK Aggregate server will push the application config-
uration on your device up to your server, replacing the configuration that is already on
your server. Once the configuration is updated, data tables on the server and device will
be synced. This process does not destroy data on the server, but instead merges changes
on the client with any existing data tables on the server (this enables you to update your
configuration without worrying about damaging or destroying the data already captured on
the server).
Return to your device, start ODK Tables:
1. Click the diminishing-lines icon to leave the custom home screen.
2. Click the three vertical dots and select Sync to launch ODK Services onto the sync
screen.
3. Choose Settings → Server Settings.
4. Edit the Server URL to be the URL for this newly configured ODK Aggregate server
(https://myodk-test.appspot.com).
5. Click on Server Sign-on Credential and choose Username.
6. Choose Username and enter the superuser username for your ODK Aggregate server.
7. Choose Server Password and enter the ODK Aggregate server password for that supe-
ruser username.
8. Click the back button until you have returned to the sync screen.
9. Click on Reset App Server to push your device configuration up to your ODK Aggregate
server.
After this has completed, you have created your own server that replicates the configuration
and contents of the https://opendatakit-simpledemo.appspot.com site. Congratulations!
Note: Any device with a user account with Administer Tables permissions can reset the
app server. If you configure a device with a user account (or Anonymous user) with only
the Synchronize Tables permissions, they will not be able to reset the app server and will
only be able to sync and join into the existing ODK-X application on this ODK Aggregate
server.
Next, we will work through the steps to configure your device with an ODK-X application
(rather than downloading an existing application from a server).
This task begins with setting up the ODK Application Designer on your computer.
For the purposes of this tutorial, we have created a copy of the Application Designer that
only contains the files for this Geotagger example (it is otherwise identical).
Read the Intro and Overview sections to get a sense of the features and functionality of the
ODK-X Application Designer environment (we will install it below). Follow this guide to
Setting Up ODK Application Designer.
Finally, follow this guide to Launching the Application Designer.
If successful, the cmd window (on Windows) should display some status messages. Below is
a screen-shot of my cmd window beginning with a dir of the contents of the directory, and
running grunt in that directory:
If a Chrome browser does not open, try manually launching it and opening http://localhost:
8000/index.html.
You can further verify that the Application Designer works by clicking on the Geotagger
button, then clicking on Follow link. This opens the Geotagger form on your computer, and
simulates all the features available to you on your device.
You can also try other things, like choosing different device dimensions to see how the form
renders on different screen geometries.
We will return to this design environment later.
Now that we have the design environment installed and functioning, and because that
environment has a copy of the fully-configured Geotagger application that is running on
https://opendatakit-simpledemo.appspot.com (minus any data that users have submitted
to the server), we can work through the steps of deploying that application to your device,
and then resetting your server to push that configuration up to your server.
First, confirm that your device has USB debugging enabled inside your device’s Settings.
This checkbox is in different places on different devices and may be hidden by default on
some. See this guide to USB debugging on Android for instructions.
Return to the cmd window on your computer. Control-C to stop the grunt command that
popped-open the Chrome browser. On Windows, you will be asked to confirm this Terminate
batch job (Y/N)?. Enter Y to confirm.
Connect your device to your computer via USB. Wait for the storage connection to be
established (on Windows, this will generally pop up a file browser or an options box that
enables you to select a file browser). Be sure you trust your computer on your Android
device, or it will cause unexpected errors.
At the command prompt, type:
$ grunt adbpush
Warning: This command will force-close ODK Services, Survey, and Tables, and it
will clear all ODK-X data from the device. The data you are pushing will overwrite any
exiting application or collected data you might have. Be sure to make backups and be
sure you are ready before running this command.
This pushes the configured ODK-X application within this ODK-X Application Designer
directory to your device. Because this is a stripped-down version of the Application Designer
that only contains the simple demo files, this will copy only those files to the device. When
you issue this command, the cmd window will display a long series of commands and conclude
with a display of overall progress and timings:
Once you have the application running on the device, you will typically need to reset the
contents of the application server. While the Reset App Server button on the device can
shuffle the various supporting files between the device and the server, it will not destroy
data tables that already exist on the server. This is intentional – we want to minimize the
potential for accidental loss of data.
Note: Whenever you are developing an application, and have found a need to add a new
column to an existing table, you will need to manually delete the data tables from the server
before using the Reset App Server button from the device.
Open a browser window to the server, log in with a user that has Administer Tables or Site
Admin privileges.
Navigate to the ODK Tables / Current Tables sub-tab.
Delete each of the tables here. In this case, there will be only one, Geotagger. The server
will now have a set of App-Level files but no data tables, forms for those tables, or data files.
Except for the app-level files, it is clean.
Note: If your table has a large number of configuration files or data rows, the server may
time out during the deletion process. In this case, the next time you try to create the table
on the server, it will resume the deletion process, and potentially time out again until such
time as it is able to finish the deletion. Only then will it re-create the table.
Now, from your device, launch ODK Tables, click on the sync icon (two curved arrows) to
launch ODK Services, make sure you are logging in as a user with Administer Tables or Site
Admin privileges, and choose Reset App Server.
The synchronization process will create the tables and push your content up to this server.
Note that the server now only contains the data rows present on the device – it no longer
has any of the additional data records from the demo site.
You have now successfully set up the Application Designer, used it to deploy an application
to a device, and, from that device, configured an ODK Aggregate server to supply that
application to other devices you join to that server.
The final task is to modify the Geotagger example by adding a new data field to it.
The overall development process is:
1. Revise the data entry form
2. Update the initialization files needed by ODK Tables
3. Update the preloaded data values as needed
4. Update the HTML to include the new field
And then follow the steps in the preceding section to deploy the modified application to the
device and push the application up to an ODK Aggregate server.
Return to your cmd window and once again launch the ODK-X Application Designer envi-
ronment (and a Chrome browser) by typing:
$ grunt
Now, open a file browser and navigate to the directory where you downloaded the Application
Designer. Then navigate within that directory to app/config/tables/geotagger. Rename
the properties.csv and definition.csv files in this directory to orig.properties.csv
and orig.definition.csv. These were the initialization files needed by ODK Tables and
they will need to be regenerated because we are altering the data table to incorporate an
additional question.
Navigate within that directory to app/config/tables/geotagger/forms/geotagger.
Open the geotagger.xlsx file in Excel (or OpenOffice). This is the form definition used
by ODK Survey.
We will be adding a question to ask the user what direction they were facing when they
took the photo. For this example, we will be collecting a text response. A more realistic
modification might restrict the user to a set of choices (North, Northwest, West, Southwest,
South, and so on).
On the survey worksheet, after the image-capture prompt, add a row that looks like the
following.
Save your changes and go back to the Application Designer. Click on the tab that says XLSX
Converter. Choose this XLSX file or use your file browser to drag and drop the geotagger.
xlsx file onto this screen (dragging and dropping is not supported on all operating systems).
You should now see some JSON in the output window. Hit the Save to File System button.
This will display three pop-up notifications announcing that the Application Designer is
1. Writing the updated ODK Survey form definition into the formDef.json file in the
same location as the geotagger.xlsx file.
2. Updating the definition.csv file.
3. Updating the properties.csv file.
Note: The definition.csv and properties.csv files are updated because the form_id
is the same as the table_id.
Go back to the Chrome Browser and click on the Preview tab. Click on Purge Database.
This will delete the earlier Geotagger data table – a necessary step because we are adding a
Direction column to that data table. Select Geotagger if you do not already have that form
open.
Create a new instance of Geotagger and advance through it (this will create the data table
with the new Direction column). Confirm that the new question is displayed. Note that the
date and description are required fields and will generate error pop-ups if you attempt to
advance through those prompts without supplying a value.
You have now successfully modified the form.
Fortunately, because the geotagger formId matches the tableId, by using the Save to File
System button on the CSV, the tool will automatically regenerate the definition.csv and
properties.csv files for this form. Furthermore, the configuration that ODK Tables uses
to specify what HTML files to use for the list, detail, and map views are all specified within
the XLSX file on the properties sheet. No manual actions are required!
Now, deploy your updated application to your device. Launch ODK Tables to initialize and
load your application. Confirm that when you edit a data row that you are now asked for
the direction in which the photo was taken.
At this point, we have added the new field to the data table, but have not yet updated the
initial set of Geotagger locations with values for that field.
Return to your Application Designer directory. Recall that when an ODK Tables appli-
cation first starts up, it reads the assets/tables.init file. That file identifies CSV files
within config/assets/csv that should be imported into the data tables upon first start-up.
Read more about importing data into a table from a CSV in the ODK Tables guide.
In this example application, the file being imported is config/assets/csv/geotagger.
updated.csv. If we wanted to, we could edit this file, add a column for the new data field
(Direction), and supply values for this field for all of the data rows that form the initial set
of Geotagger locations.
Alternatively, we can return to the device and use the CSV export functionality within
ODK Tables to export the CSV file (into /sdcard/opendatakit/default/output/csv).
Then pull it off the device and overwrite the CSV file under the Application Designer at
Warning: Some CSV editors, like Office or OpenOffice, may convert or alter the
content inappropriately when you save changes. If your edits cause the device to fail to ini-
tialize the data fields, you may need to make this edit manually using a less-sophisticated
tool or choose different options when saving your changes.
There are two areas where image information is displayed, one is in the list view, where
you can expand or collapse an item, and the other is in the detail view, which is opened
when you click or tap on an expanded item in the list view. We will only modify this detail
view to report the image direction. A more comprehensive edit would likely also update the
expanded item within the list view.
To determine all the HTML files, we can begin with the files referenced in the properties.
csv file we recently finished editing. Looking again at that file, we see three files referenced:
• tables/geotagger/html/geo_list.html
• tables/geotagger/html/geo_list_thumbnail.html
• tables/geotagger/html/geo_detail.html
Each of these files, or the JavaScript within them, might open or reference other files that
might need to be updated. The above files are simply the ones we know are reachable.
In general, files for displaying table-specific data are under the config/tables/tableid
directory. In this example, we will modify the last of these files and its associated JavaScript
file.
Open a file browser and navigate to the directory where you downloaded the Application
Designer. Then navigate within that directory to app/config/tables/geotagger/html.
Open geo_detail.html in a text editor. Insert a line that defines a DIR element above the
Latitude line in the HTML body region. This will be where we will display the value of the
Direction field. For example:
<h1><span id="TITLE"></span></h1>
<p>Image Direction: <span id="DIR"></span></p>
<p>Latitude: <span id="FIELD_1"></span></p>
Save the file. Once again, push the application to the device. Confirm that when you expand
a item in the map list window, and then tap on that expanded item, that it now shows Image
Direction:. (See example below.)
Congratulations, you have successfully modified this ODK-X application to add a new data
field and display it as a field in the HTML detail-view page.
You could now log onto your server, delete the geotagger table, reset your server, and start
collecting geopoints with the new image direction field.
grunt addtable:tableid : Will create the required directory structure for an individual table,
including the forms directory.
grunt xlsx-convert-all : Takes all .xlsx files and converts them into a formDef.json file. Can
be used instead of XLSX converter on the app designer.
grunt wipe-data : Allows users to get rid of the default tables/data included with app
designer.
grunt setup : Launches the login and sync screen on the connected device.
grunt kill all : Force stops survey, tables and services on the connected device.
grunt uninstall : Uninstall ODK tools from the connected device.
Survey and Tables each have a basic sample application that walks through their features:
• ODK Survey: Sample Application
• ODK Tables: Sample Application
To get started building applications, first set up the ODK Application Designer. After you
have familiarized yourself with that tool, you can try building and deploying an application:
• Building an Application
A more complete guide to using ODK XLSX Converter is provided in the ODK XLSX
Converter documentation. More details about Tables web views are available in ODK Tables
Web Pages and Injected JavaScript Interfaces.
For examples of real world applications and details about they are implemented, try out the:
Reference Applications.
We also provide guides geared towards Deployment Architects for each of the Android and
Desktop tools.
• Managing ODK Survey
• Managing ODK Tables
• Managing ODK Services
• Managing ODK Scan
However the user guides for these tools are also useful for everyone.
Finally, to expand your knowledge of the more advanced features of the platform, such as
data permission filters, read the Deployment Architect Advanced Topics.
ODK Survey is an Android application for performing data collection in the ODK-X frame-
work. It operates similarly to ODK Collect, but is based on HTML, CSS, and Javascript
rather than native Android, and is more flexible in its presentation and execution.
Note: ODK Survey only works on Android 4.2 and newer devices.
Note: ODK Survey cannot read or display the forms created for ODK Collect (that is,
those created via ODK Build, XLSForm, or other form design tools). ODK Survey operates
with ODK-X Data Management Applications*.
Prerequisites
Required
Before installing ODK Survey, you will need the following ODK Tools:
• ODK Services
As well as the following third party apps:
• OI File Manager
Recommended
Note: You can also download the ODK Survey APK to your computer and load it on your
device via adb or another tool like AirDroid.
Tip: You can also install ODK Survey on an Android emulator. However, this can be slow
and is only recommended for developers actively working on Survey.
In this guide we will be demonstrating how to use ODK Survey via a guided tour of a sample
application. This guide demonstrates both the general workflow of Survey and some of the
features that differentiate it from ODK Collect.
Warning: ODK Survey performs a similar role to ODK Collect in the ODK-X Tool
Suite. However, it is more complex and not every organization will need its features. The
choice of whether to use ODK Collect or ODK Survey and the ODK-X tools should be
made carefully based on your organization’s needs. A brief comparison can be found in
the guide for Selecting the Appropriate Tool Suite.
Prerequisites
Install ODK Survey and its prerequisites from the guide: Installing ODK Survey.
We have provided a sample application to help you acquaint yourself with the various features
of ODK Survey. This sample app contains six sample forms within it:
• Example Form – a form with many examples of data entry widgets.
• Grid Screen Form – a form used to demonstrate a new screen layout that allows
fully customized prompt placement.
• Household Survey – a form used to gather information about a household. To
operate correctly, this requires the Household Member Survey sub-form and the Ed-
ucation sub-form (you should not open those sub-forms directly – they are launched
from within Household Survey).
• Select Examples – a form with several examples of select widgets, including widgets
that access data on Yahoo servers, and others that access CSV files for their choice
lists. It also demonstrates the use of custom CSS styles to change the look of the form.
• Household Member Survey – a form used to gather information about household
members. This is a sub-form of the Household Survey form (you should not open
it directly – it is launched from within Household Survey). ODK Survey eliminates
the repeat group concept and replaces it with sub-forms. From within the Household
Survey you navigate into this sub-form by entering information about individuals in a
household.
• Education – a form used to gather education information about household members.
This is another sub-form of the Household Survey form (you should not open it directly
– it is launched from within Household Survey). This sub-form saves information to the
same underlying data table (household_members) as the Household Member Survey
form, but it asks different questions. This demonstrates the use of multiple forms to
revise different sets of values within a data table. From within the Household Survey
you navigate into this form when you enter education information about individuals
in a household.
Note: Since the Education and Household Member Survey operate on the same table, you
will only see five tables in ODK Tables and in the Cloud Endpoint even though there are
six forms.
Learn More
For instructions on creating your own Survey applications, view the ODK Survey: Designing
a Form guide.
Unlike ODK Collect, the ODK-X tools are application-focused. An application is identified
by the name of the directory under the /sdcard/opendatakit/ folder. The sample applica-
tion is named default, as is the sample applications provided for ODK Tables. This means
that you can only deploy one of these sample application at a time onto a device. We also
provide instructions to rename one of these so that two or more applications can co-exist
and not interfere with each other on this same device.
To access the sample application and its six sample forms:
1. Launch ODK Survey. Press the Settings button that resembles a gear. This
will launch the ODK Services tool to the settings page.
2. Select Settings -> Server Settings (more info on setting up your server can
be found here: Server Configuration)
• Set your Server URL to https://opendatakit-2.appspot.com.
Note: The server URL starts with https:// not http://. Don’t forget
to include the s.
When that is completed you should now be presented with the list of those six sample forms.
Learn More
For instructions on installing your own Survey application to a device, view the Moving Files
To The Device guide.
Opening a Form
Open Survey. If you have successfully installed the sample application, you should be pre-
sented with a list of the six sample forms.
Note: The Household Members and Education forms are not intended to be called directly,
but are launched from within the Household form.
To open a form, tap on it in this list. For this tutorial, open the Example Form.
This screen shows the name and version of the form you are viewing. If you scroll down you
will see a list of previously created instances of this form.
Tip: Form instances can always be edited, even after they have been finalized.
Learn More
For more detailed instructions on opening and modifying Survey form instances, view the
Opening a Form guide.
Navigating a Form
Forms in Survey are defined in HTML, CSS, and JavaScript. A default look-and-feel, along
with an extensive selection of prompt widgets, is provided by the ODK-X framework, but
this can be customized by your organization.
To navigate forms using the default look-and-feel:
• Tap on the name of the survey in the top left to access a pop-up menu of options.
• Tap the Back or Next buttons in the top right of the form to navigate through the
form.
Let’s fill out the instance of the Example Form that we opened in the previous section. After
tapping the Create new instance button you should see the following screen:
Use the Next button in the top right to progress to the first question.
Initial Value
This prompt asks you to give the form an initial rating. Its purpose in this example is to
show how Survey can use previously collected data to populate and calculate later fields.
Enter any number you like and it will be used later.
Press the Next button in the top right to progress to the next question.
Prompt Selection
This prompt allows you to choose which sections of the form to complete. Survey form
navigation can be completely customized, even at runtime, to include or exclude sections,
repeat portions, jump directly to different prompts based on entered values, and more. For
this example we will complete the label features, computed assignment of initial values, and
custom template sections. However, feel free to enter any combination you like and explore.
Press the Next button in the top right to progress to the next question. Note that we skip
the intent launching section and progress directly to label features.
Label Features
This prompt shows that the label and hint fields of the prompt can be customized by editing
the HTML and CSS. This allows your organization to modify the look-and-feel of the prompts
to suit their needs.
Press Next to see a more complex example:
This prompt shows a label that has been edited to include media files including an image
and an audio clip. Press play on the audio clip to hear a bird call. However, media can also
be added via spreadsheet columns, which is generally easier.
Press Next to advance to the next section.
This prompt is requesting a value that will be used to render the next question. Enter any
name you like and press Next.
This prompt shows that a prompt can use a previously collected value in the rendering of a
prompt. For example, a subject’s name and gender could be used to properly address them
throughout a survey.
Press Next to see another example of data reuse.
This prompt is requesting a value that will be used to render the next question. Enter any
value you like and press Next.
This prompt will prepopulate the entered data with the value from the previous prompt.
In general, you can prepopulate a prompt with any previously collected value. In another
example you might record a subject’s address and then prepopulate that address on their
household members address prompts.
Press Next to advance to the next section.
Custom Template
This prompt is requesting data that will be used in the next prompt to render a custom
template. We will also use this to demonstrate constraints. Enter an age that is greater
than 20 and press Next.
Survey will not allow you to progress until you’ve entered a valid value. This validation
can be done dynamically as well. For example, you could have a running average of crop
heights you have measured, and disallow crop heights that differ by more than three standard
deviations.
Enter a valid age, weight, and height, and press Next.
This prompt will show the data point you entered in the previous prompt, rendered on a
plot of average weights. This is a custom prompt defined in JavaScript for this example, it
is not a default display option provided by the ODK-X framework. It demonstrates that
Survey can be customized to whatever level your organization requires without the effort of
rewriting and recompiling the Android tools.
Press Next to advance to the next section.
Update Value
This prompt is prepopulated from the initial value we entered in the first prompt. Whatever
you entered for that field will be filled in here. Updating this field will update the value in
the database.
This was the final prompt for this example. Press Next to advance to the final screen of the
form.
This screen tells you that you have reached the end of the form. This does not mean
that you have entered data for every field. In this example we skipped the majority of the
questions. From here you can navigate backwards and update any of your previous answers.
You can also use the button in the upper left to navigate to previous questions or leave the
form instance.
Warning: Updating answers may cause later prompts to render differently or be inval-
idated.
Learn More
For more detailed instructions on navigating Survey forms, view the Navigating a Form
guide.
This concludes the guided tour of the sample application for Survey. However, this is far
from a complete reference. Please continue to explore the different forms and prompts to
learn more about the tool’s capabilities.
You can find a more detailed user guide for Survey here: Using ODK Survey. And you can
find a more detailed guide to managing Survey for Deployment Architects here: Managing
ODK Survey. You can also find the sample forms shown in this tutorial in the Github
repository for App Designer.
Warning: Survey forms are defined in HTML, CSS, and JavaScript that can be edited
by your organization. If the interfaces displayed in this guide do not match the form you
have on your device, contact an administrator in your organization for further guidance.
• Opening a Form
– Opening a Subform
• Saving a Form Instance
• Viewing Saved Form Instances
– Editing Saved Form Instances
– Deleting Saved Form Instances
• Navigating a Form
• Syncing Forms and Data
Opening a Form
The home screen of Survey displays a list of all the forms available on the device.
Note: Not all forms listed on this home screen are intended to be launched directly.
Subforms will be listed on this page but are generally intended to be opened from within a
parent form.
To open a form tap its name on the list. This will launch the home screen of that particular
form. Below we have opened the Example Form.
This screen shows the form name and version. It also shows a full list of saved instances of
the form. For more information on viewing and editing these form instances see the section
on Viewing Saved Form Instances.
To start a new instance and begin filling in a form, tap the Create new instance button.
Opening a Subform
Unlike their parents, subforms are generally not intended to be opened from the Survey home
screen’s form list. Instead, subforms are integrated into their parent forms and launched
directly as prompts. They integrate seamlessly into their parent forms and do not need to
be manually opened. They might be indicated by a Create new instance button within a
form, or the form may directly launch the subform.
For example, the Household Member Survey is a subform of the Household Survey in the
Survey sample app.
This screen within the Household Survey shows the launcher for the Household Member
Survey subform. Clicking Create new instance will launch the subform.
This is the first page of the Household Member Survey subform. It displays the name of the
household, Sample House, which was collected in its parent Household Survey form. After
this subform has been filled in, the flow will return to the parent form.
Completing the Household Member Survey subform returns us to the same screen we launched
from in the Household Survey. The instance created by the subform is now displayed. If you
tap the Create new instance button again, you can create multiple instances.
When saving a form instance, you can either mark it as Finalized or Incomplete.
• Finalized forms indicate that they are completed and that the data should be used
and aggregated.
• Incomplete forms indicate that the form has been saved but it is not yet complete.
This is useful if you need to stop filling out a form and return to it later, but want to
keep your previously collected values.
Note: Marking a form as Finalized does not prevent you or another user from modifying
it later.
2. Tap the button with the name of the form in the upper left from any screen in
the form. This will open a menu that provides navigation and exit options.
• To save the form as Incomplete choose Save Change + Exit
• To save the form as Finalized choose Finalize Changes + Exit
3. Press the Android back button. This is not the Back button provided by
ODK in the upper right. This is the button to back out of apps. This will
launch a menu with the option to Save Changes which will save the form as
Incomplete.
Note: This menu does not have an option to save a form as Final-
ized.
A list of previously saved form instances is viewable on the home screen of each form. Open
the desired form (instructions in the Opening a Form guide) to see this list.
Warning: This list of saved form instances is not limited to those collected
on your device. After synchronization this will include all form instances
from all devices that have synced with the server. Take care not to edit form
instances that you should not be editing.
To protect against unauthorized edits, see Data Permission Filters.
This list of instances is ordered reverse chronologically by the last save date, with the most
recently edited form instance on top and the oldest form instance at the bottom. These
instances are marked as either Finalized or Incomplete (see Saving a Form Instance for
definitions).
To edit a form instance, tap the pencil icon next to the instance in the instance list on the
form home screen.
This will launch that instance with all collected values prepopulated. When you save this
form as either Finalized or Incomplete, that state will overwrite the previous state of
Finalized or Incomplete. The updated form instance will now be the most recently edited
form and appear at the top of the list.
To delete a form instance, tap the X icon next to the instance in the instance list on the
form home screen.
Navigating a Form
Forms in Survey are defined in HTML, CSS, and JavaScript. A default look-and-feel, along
with an extensive selection of prompt widgets, is provided by the ODK-X framework, but
this can be customized by your organization. This guide assumes you are using the default
look-and-feel.
• To advance to the next prompt in a form, press the Next button in the upper right.
• To go backward to the previous prompt, press the Back button in the upper right.
• To navigate to a specific prompt, press the button on the upper left with the form
name to show the menu. Tap the button labeled Contents.
This will bring up a menu with a full list of fields and their recorded values. Tap the
desired field to navigate to it in the form.
Every change you make to the data in the form is written immediately to the database as a
checkpoint save.
Warning: If a data table has any checkpoint saves (for example, caused by form
crashes), the data table will not be synchronized. Checkpoints must be resolved before
sync can proceed. The user must open a form on the problem table and either delete the
checkpoint or edit the checkpoint. If editing, after that is complete they must save is as
either incomplete or finalized. Once the checkpoints are eliminated, the user can initiate
another synchronization, and the data in this table will then be synchronized with the
information on the server.
• Prerequisites
– Required
– Recommended
• Setting up a Form Development Environment
• Designing a Form
– Full XLSX Reference
• Launching With a Different AppName
– Android 4.x Devices
– Android 5.x and Higher Devices:
– Trying the New Launcher
– Making a New AppName
Prerequisites
Required
To create an Data Management Application that uses ODK Survey, you will need the ODK
tools:
• ODK Services
• ODK Application Designer
• ODK Cloud Endpoints
As well as the third party apps:
• OI File Manager
If you have not installed Survey already, follow our guide for Installing ODK Survey
Recommended
We also recommend:
• ODK Tables
ODK Tables is not required, but Tables and Survey are built to seamlessly integrate and
support more robust Data Management Applications.
To get started creating your own Data Management Applications, go to the ODK Application
Designer documentation.
Designing a Form
Basic instructions for designing Survey forms are provided in the ODK Survey: Designing a
Form.
Survey forms are created in Excel and saved as .xlsx files. These are converted into form
definitions using the ODK XLSX Converter. The linked guide should help you create and
modify the files to create your own forms.
Use the ODK XLSX Converter Reference to find all the features you can use in your Survey
forms.
The ODK-X tools are designed to support multiple independent Data Management Applica-
tions running on the Android device. Each of our tools has the ability to run in the context
of either a default application name, or a specified application name.
By default, ODK Survey runs under the default application name (as does ODK Tables and
the other ODK-X tools). Application names correspond to the name of the directory under
/sdcard/opendatakit where the configuration and data files for that application are stored.
Warning: Though the Android tools support multiple AppNames on the device, each
ODK Cloud Endpoints only supports one AppName at a time. For each application you
have running on the device, you will need a new Cloud Endpoint that is configured with
that AppName.
Each Data Management Application will store its own server configuration. Therefore
after an initial setup that points each application at its proper server, the user will not
need to remember which server hosts which app.
Here we describe how to launch the ODK-X tools into an application name of your choice
with the use of widget shortcuts.
First, you must create an alternative application. As a contrived example, we will make an
exact copy of the default application on the device with a new name. To do so, first load an
application to the device (such as the sample application). Then open OI File Manager,
navigate to the /sdcard/opendatakit directory, and copy the default directory, renaming
it myapp. You have now created the myapp application! It is isolated from and operates
independently of the default application.
To launch and use that application:
Now, play around with launching ODK Survey using this application shortcut and Finalizing
a new filled-in form. Exit ODK Survey, and launch it from the applications list (so that it
launches as the default application). Verify that you do not see that newly filled-in form.
You can also create a new filled-in form in this default application and confirm that it is not
visible in the myapp application.
This highlights the isolation of Data Management Applications in the ODK-X tools. This is
even more powerful with applications that use ODK Tables because you can create entirely
isolated applications, such as a forestry app and a health clinic app, and have the forms and
data entirely independent of each other.
This eliminates the need for different groups to fork the ODK code base.
1. Download a new copy of ODK Application Designer. Clear out the config
directory as you normally would.
2. Open app-designer/gruntfile.js.
3. In the modle.exports function, find the variable tablesConfig.
4. Modify the value of appName in variable tablesConfig. This value starts
as default. Set it to the desired new AppName.
5. Save Gruntfile.js
6. Develop your Data Management Application and push it to the device the
normal way (instructions in the guide).
Using the above technique will keep your apps cleanly separated. You can also maintain
multiple Data Management Applications in the same Application Designer instance by mak-
ing alternative app-designer/app directories and creating new Grunt tasks to push them
to the device.
ODK Tables is a program that allows you to visualize and update existing data. Using Tables
as your entry-point to data collection, you will be able to gather data using ODK Survey,
sync it to a server using ODK Services, and have other users download and edit this same
data on their own devices.
Tables also enables web developers to build powerful data management applications to handle
their complex workflows. While Survey follows a traditional data collection workflow, similar
to that of Collect, Tables gives you the flexibility to implement your own arbitrary complex
workflow. For example you might collect data via a customized mapping interface: Tables
allows you to build an application using web technologies to achieve that.
Note: ODK Tables only works on Android 4.2 and newer devices.
We have included a sample application built on top of Tables along with a handful of data
tables that showcase some of its features.
Prerequisites
Required
Before installing ODK Tables, you will need the following ODK Tools:
• ODK Services
As well as the following third party apps:
• OI File Manager
Recommended
Note: You can also download the ODK Tables APK to your computer and load it on your
device via adb or another tool like AirDroid.
Tip: You can also install ODK Tables on an Android emulator. However, this can be slow
and is only recommended for developers actively working on Tables.
In this guide we will be demonstrating how to use ODK Tables via a guided tour of a sample
application.
Prerequisites
Install ODK Tables and its prerequisites from the guide Installing ODK Tables.
We have provided a sample application to help you acquaint yourself with the various fea-
tures. This sample app contains five demo apps within it.
• Tea Houses - a fictional Benin Teahouse directory. It provides a broad overall view
of the different view types that Tables offers.
• Hope Study - a simplified subset of a perinatal follow-up application that was piloted
on ODK Tables and ODK Collect (now converted to use ODK Survey). It demonstrates
how Tables and Survey can be integrated.
• Plot - a fictional agricultural field pest- and yield- assessment application. It demon-
strates how data can be visualized and actively updated as it is collected on the device.
• Geotagger - a simple geotagging application. It demonstrates a basic customization
of the user interface with HTML, CSS, and JavaScript.
• JGI - an app used to track the daily behavior of chimpanzees. It uses a complex, fully
customized and domain specific user interface. It also demonstrates Tables collecting
data for multiple data tables and rows simultaneously (as opposed to the single row
editing of Survey).
Unlike ODK Collect, the ODK-X tools are application-focused. An application is identified
by the name of the directory under the /sdcard/opendatakit/ folder. The sample applica-
tion is named default, as is the sample applications provided for ODK Survey. This means
that you can only deploy one of these sample application at a time onto a device. We also
provide instructions to rename one of these so that two or more applications can co-exist
and not interfere with each other on this same device.
We will use the ODK-X synchronization mechanism to install this app. It is about 26 MB
in size and takes a few minutes to download from the web.
1. Launch ODK Tables. Press the Action Button (�) and press Preferences
from the menu.
Note: The server URL starts with https:// not http://. Don’t forget
to include the s.
After this configuration is set up, ODK Tables should now present a custom home screen
with five tabs, one for each of the demos. If it does not, back out of ODK Tables and
re-launch it.
Learn More
For instructions on installing your own Tables application to a device, view the Moving Files
To The Device guide.
Open Tables. If you have successfully installed the sample application, you should be pre-
sented with a custom home screen showing the five demo apps.
Tables allows your organization to customize the home screen of your Data Management
Application. By default Tables will only show a list of the data tables defined on the
device (called the Table Manager). But with a custom home screen your organization can
implement their own complex workflow and look-and-feel with HTML, CSS, and JavaScript.
An example of this is what is displayed after downloading the sample application.
Note: All of these screens and web pages are served directly from the device – there is
no network access. These are fully able to function in Airplane mode – without a WiFi or
internet connection.
When you design your applications, you can either have them operate without any network
access, or you can write them to access data on the internet. This becomes your design
choice.
Each tab on this screen is the home page for one of the five demo applications listed above.
Note: For this example we have included all five applications under the same AppName.
However, typically you would give them each their own AppName to provide a clean sepa-
ration of data.
Learn More
For more information about custom home screens, view the Custom Home Screen guide.
For this portion of the tutorial we will explore the Tea Houses demo. Select the tab labeled
Tea and press Launch Demo.
The Tea Houses demo is a fictional collection of Tea Houses in Benin and the teas they offer.
Custom View
The first screen you will see after launching the Tea Houses demo is a custom view.
As with the custom home screen, this custom view is rendered entirely in HTML, CSS, and
JavaScript defined within the Tea Houses demo. It does not collect or present data, it acts
as a navigation screen to allow the user to choose which of the three data set to interact
with.
Custom views are not limited to navigation and workflow interfaces. They can also be used
to view data, create data visualizations, and modify data in the database. The Plot Demo
and JGI Demo explore this more fully.
Press the button labeled View Teas to launch the List View of the available teas.
Learn More
For more information about custom views, view the Custom View guide.
List View
This screen shows a list of all teas available in the Tea Inventory data table. This view is
customized with HTML, CSS, and JavaScript. It provides a simple way to view and navigate
collected data. As new teas are added to the inventory, this list view will grow.
To see the raw data, we will switch to Spreadsheet View. Tap on the lined paper icon at the
top of the screen. Here you’ll see all the possible view types. Select Spreadsheet.
Learn More
For more information about List Views, view the List View guide.
Spreadsheet View
This view renders a full data table from the database, including all rows and columns. Unlike
the views we have seen so far, this view is NOT customized via HTML, CSS, and JavaScript.
This view is provided by the ODK-X platform for convenience in viewing and editing your
data directly. It is meant to be a familiar view as if you were looking at it on a spreadsheet
program, such as Excel. Each row here represents a tea, and each was a row in the List
View.
Return to the List View by using the lined paper icon as before and selecting List. Tap the
Stonehouse tea to launch a Detail View for that tea.
Learn More
For more information about Spreadsheet View, view the Spreadsheet View guide.
Detail View
This screen shows all the details of the Stonehouse tea entry in the Tea Inventory table. The
Tea Inventory table’s Detail View displays information about the tea, including whether it is
available hot, iced, in bags, or loose leaf. Note that the tea type is being pulled from the Tea
Types table, but the JavaScript is getting the information from that table to construct our
view. Like the other views, we programmed this using rudimentary HTML and JavaScript,
but it could be customized to look fancier or display additional information.
Next we will see a combination of the detail and list view options. Back out until you hit
the custom view with the three buttons. .. _tables-sample-app-detail-view-learn-more:
Learn More
For more information about Detail Views, view the Detail View guide.
From the custom view with the three buttons, select View Tea Houses. This will launch
another List View, this time showing the list of tea houses.
The Tea Houses table has been configured to use a Detail With Sublist View rather than a
Detail View. Tap the Tea for All tea house to see this.
This screen contains a Detail View webpage and a subordinate List View. In this case, the
Detail View displays information on the tea house, and the List View displays the teas that
the tea house serves. Within the Detail View, you can scroll down to see the information we
decided to display. It is also written in HTML, CSS, and JavaScript to render these table
entries. The look-and-feel is similar to the Tea Inventory only because that is how we coded
it. Like the List View, we programmed this using very rudimentary HTML and JavaScript,
but it could be customized to look fancier or display additional information.
Scroll to the bottom of the Detail View portion of the screen and you’ll see a link as a number
of teas. This is using the information in the table called Tea Inventory to tell you how many
teas this tea house offers, and has also been defined in the JavaScript.
The bottom half of the screen renders the subordinate List View, which shows the list of
teas available at the Tea for All teahouse. It is a separate page that is controlled by the top
half.
Note: This is a simple example that has a static list. However, you could dynamically
change the list that is rendered with controls in the JavaScript for the top half of the screen.
For example, you could have a household detail on top, and list all family members on the
bottom. You could then provide a button to change the list to only show adult family
members in the list below.
Next we will see the Map View. Back out of the Detail With Sublist View to see the list of
tea houses. Press the lined paper icon and choose Map from the menu.
Learn More
For more information about Detail With Sublist Views, view the Detail With Sublist View
guide.
Map View
All the fictional tea houses in Benin appear on the map. Pinch and squeeze or widen to zoom
out and in, respectively. The tea house location is plotted based on what appeared in the
Location_latitude and Location_longitude columns in the database. These can be viewed
with the Spreadsheet View. When you click on a map marker, the List View will redraw with
that marker’s information at the top of the List View.
The List View at the top portion of the screen is rendered in custom HTML, CSS, and
JavaScript, but the map portion is provided by the ODK-X platform and rendered using
Google Maps.
Learn More
For more information about Map Views, view the Map View guide.
The final portion of the Tea Houses demo will be to edit data with Survey. Return to the
List View by using the lined paper icon as before and selecting List. Tap the Tea for All tea
house to launch a Detail With Sublist View for that tea. Tap the pencil icon in the upper
right.
This will launch Survey to edit the Tea for All row in the Tea Houses data table.
This Survey form allows you to edit any and all of the data fields in the Tea for All entry.
Navigate to the question that reads:
Which tea is the house specialty
Change the specialty to be Herbal. Complete the form and finalize the changes. When you
return to the Tea for All detail page you will see the house specialty has been updated to
Herbal.
Similarly, this action can be taken from a List View by using the + button in the upper
right.
Tables and Survey are built to integrate seamlessly. Data can be visualized in Tables and
edited in Survey, with your organizations complex workflow moving between as needed. A
more complex example of this will be shown later in this tutorial with the Hope Demo.
Note: Survey is often the easiest way to edit data. However, Tables offers JavaScript APIs
to directly edit data through your own custom user interfaces.
This concludes the Tea Houses demo. Next we will open the Geotagger Demo.
Learn More
For more information about launching Survey from Tables, view the Editing With Survey
guide.
Geotagger Demo
For this portion of the tutorial we will explore the Geotagger demo. Select the tab labeled
Geo and press Launch Demo.
The Geotagger demo is a mapping of sites around the city of Seattle (and anywhere else
anyone has recorded and uploaded to the server).
Navigate View
After launching the Geotagger demo app, you will see a Map View of the points in Seattle,
or possibly a larger space. To switch to Navigate View, tap the lined paper icon in the upper
right and choose Navigate.
You will see the same map on the bottom portion of the screen, but the top will be replaced
by a compass and heading readouts.
As you turn the compass should update. If you select a point, the compass will add an
arrow pointing towards the selected point from your current orientation. The Distance and
Heading values should fill in as well, and update as you move around.
The Navigate View can be useful if you have loaded geopoints into your database (either
preloaded or collected in the field) and you need to find your way to these points. It can be
integrated into other workflows to navigate a worker to a point and then launch them into
another data collection activity.
Tip: The Geotagger demo also has a more complex Map View example. If you select
Map View and tap on a map marker, that location will be highlighted in the List View on
the top of the screen and it will expand to give you more information about it. This more
sophisticated behavior is all performed in the JavaScript and HTML files.
Learn More
For more information about Navigate View, view the Navigate View guide.
Plot Demo
For this portion of the tutorial we will explore the Plot demo. Select the tab labeled Plot
and press Launch Demo.
The Plot demo is a fictional collection of crop data and graphs of that data.
Graph View
After launching the Plot demo app, you will see a custom view that lets you select which
crop data you want to see. Choose View Plots.
The next screen is a Map View of the different sites in the records.
Each site is meant to represent an area where crop growth and health is being tracked. This
provides a convenient view of the locations of the sample sites, and would be a good use for
the Navigation View if a user had trouble finding one of the sites. Choose the Ungoni site.
The screen shows a Graph View of the crop height data collected for the Ungoni site. The
bar graph shows corn crop heights across three different visits to this farm.
Tip: The graph was rendered using the D3 JavaScript library. That library can render
scatter plots, line graphs, graphs with error bars, and many other visualizations.
The graph was rendered on the device based on collected data. If new data is collected this
graph will be updated. To demonstrate that, let’s perform a new visit. Scroll down the page
and press the New Visit button.
100 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
This will launch Survey to a form that the Plot application specified. Advance through the
form. Notice that some of the fields are prepopulated, such as the plot being observed. Be
sure to leave that set to Ungoni.
When you reach the prompt asking for crop height, enter: 130.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 101
Chapter 4. Trying It Out
Advance through the rest of the form, entering any data you like. Finalize the changes.
When you return to the Graph View notice that a new visit has been added to the graph.
102 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Tour the rest of the Plot demo to see a variety of other Graph Views. These are all rendered
in custom JavaScript, and could be customized to your organization’s unique needs.
Next launch the JGI Demo to see a demo of data collection directly through Tables.
Learn More
For more information about Graph View, view the Graph View guide.
JGI Demo
For this portion of the tutorial we will explore the JGI demo. Select the tab labeled JGI
and press Launch Demo.
The JGI demo is a prototype of an application used by the Jane Goodall Institute to collect
information about Chimpanzee behavior in the field.
After launching the JGI demo app, you will see a custom view where you can choose to
continue or start a new Follow. Choose New Follow.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 103
Chapter 4. Trying It Out
The next screen will prompt you to enter data about the Follow you are about to perform.
104 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Note that we haven’t launched Survey, this data is being collected by custom fields written
in HTML, CSS, and JavaScript and rendered directly in the Tables view. Additionally, this
data is not being used to create a single row in a single data table, it is going to be used by
the following screen’s JavaScript code to write to multiple rows in multiple data tables.
When you have filled in these data fields, press Begin. This will show start the Follow
workflow.
This screen is hard not intuitive for a new user to understand. It is highly customized to
the specifications of the Jane Goodall Institute’s workflow. They originally used large paper
notebooks with grids. They would check boxes on the grid based on observed chimpanzee
behavior according to their own data collection protocols. This screen renders that same
grid digitally and gives a worker access to dozens of fields simultaneously. Survey, Collect,
or other form based data entry models would be too scripted and confining for this type of
dynamic interaction record. Furthermore, this screen will advance to a new data point every
15 minutes. This is another workflow necessity that is only possible because of customized
JavaScript.
Finally launch the Hope Demo.
Learn More
For more information about customized forms of data entry, view the Editing Directly in
Tables: Custom Views guide.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 105
Chapter 4. Trying It Out
Hope Demo
For this portion of the tutorial we will explore the Hope demo. Select the tab labeled Hope
and press Launch Demo.
The Hope demo is a complex, longitudinal medical survey involving mothers with HIV.
After launching the Hope demo app, you will see a custom view that lets you choose whether
you are visiting with a new client or following up with an existing client. This study involves
multiple visits from the same patient that occur over a period of months during and after
the mother’s pregnancy. Let’s imagine that a client with ID number 44176 has come in for
a 6 week follow up visit.
Select Follow Up with Existing Client.
106 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
This will open a List View that shows all the registered clients in the system (registered
using the Screen Female Client option from the previous screen).
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 107
Chapter 4. Trying It Out
On the top of the screen is a search field that is custom written in HTML, CSS, and
JavaScript. Use this to enter the client ID of the patient we imagine to be interviewing:
44176. After pressing Search the desired client should be visible.
108 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
This page is a Detail View, but most of the collected data about this patient is not shown.
Instead, links to the follow up Survey forms are provided to make follow up visits run
smoothly. If you needed to update the patient’s information, you could tap the pencil icon
in the top right to launch the Survey form containing all of that patient’s data.
Tap Client Forms and choose Six Week Follow-Up. This will launch the Survey to the specific
form containing the six week follow-up questionnaire.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 109
Chapter 4. Trying It Out
This demo imitates a single visit. Next you can try to emulate the full length of the study
for a single patient from the initial screening through all the follow up visits. Notice that
the Graph Views will update with this new information as well.
Learn More
For more information about integrating Survey and Tables, view the Creating and Editing
Data guide.
This concludes the guided tour of the sample application for Tables. However, this is far
from a complete reference. Please continue to explore the demo applications to learn more
about the tool’s capabilities.
You can find a more detailed user guide for Tables here: Using ODK Tables. And you can
find a more detailed guide to managing Tables for Deployment Architects here: Managing
ODK Tables. You can also find the source code for the demo applications in this tutorial in
the Github repository for App Designer.
110 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
The custom home screen is an HTML file written by your organization to customize the
look-and-feel of using Tables. If a custom home screen is provided, by default it will be the
first screen shown after opening Tables.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 111
Chapter 4. Trying It Out
To hide the custom home screen and see the Table Manager for a list of data tables on the
device:
1. Open Tables. On the custom home screen press the button with three lines
in the upper right.
2. The Table Manager will be visible with a full list of data tables stored on
the device.
112 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
To return to the custom home screen press the back button in your Android navigation
buttons.
Warning: You may need to enable the custom home screen before it will appear.
To enable or disable the use of the custom home screen, follow the instructions for Tables
Settings.
Table Manager
The Table Manager allows you to modify table settings, delete tables, and import or export
data into your tables. See the Deployment Architect instructions for details.
Viewing Data
Tables supports viewing collected data in a variety of formats. Survey allows you to review
individual form instances, but Tables lets you view full data tables as well as create your
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 113
Chapter 4. Trying It Out
own customized visualizations. This is a significant departure from the form based model of
data collection, and allows you to manage data directly on the device.
View Types
Tables offers a number of view options for presenting data. These will have been configured
by your organizations Deployment Architect and you may not always have a choice in how
you view your data. These view types are:
• Spreadsheet View
• List View
• Detail View
• Detail with Sublist View
• Graph View
• Map View
• Navigate View
• Custom View
Warning: Many of the view types in Tables are customizable by a Deployment Ar-
chitect. This guide will provide some basic outlines of how to use these view types, but
for more accurate instructions you may need to contact your organization’s Deployment
Architect.
Spreadsheet View
Spreadsheet View is the only view option that will be the same for all Data Management
Applications. It is not customizable. It serves as a reliable way to view all of the data stored
in a table on the device.
114 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
It is intended to have the familiar view as if you were using a spreadsheet program such as
Excel. Each row represents a data record, which often (but not always) corresponds to a
form instance created by Survey. You can scroll up and down to view all of the records, or
left and right to see each column.
The thin column on the left is called the status column: it will show a different color based
on the status of that row.
• White (clear) – The row is downloaded from the server and has not been modified.
• Yellow – The row is modified.
• Green – The row is an entirely new row
• Black – The row is deleted. It will show as black until you sync with the server and
publish those changes.
Custom color rules can be set in table properties. They change the colors of spreadsheet
cells based on the values of those cells. This can be useful in browsing larger data sets for
records that meet certain criteria. For example, you might be recording crop heights and
mark all cells with heights above a certain height as impossible so that they can be revisited
or removed. For details on setting these color rules, see the color rules guide
Spreadsheet view can also be used to edit data. See the Spreadsheet View editing guide for
further instructions.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 115
Chapter 4. Trying It Out
List View
List View is a customizable view that will change based on your Data Management Appli-
cation’s code. In general, it is used to render a list of records from a data table, displaying
only a few key values for each record.
116 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Often the items in a List View are clickable to launch a Detail View, a Detail With Sublist
View, or a Custom View to display details of that item. Sometimes these views can also be
viewed as Map Views and Navigation Views. See Changing View Types: The Lined Paper
Button for instructions on how to find if these view options are available.
Detail View
Detail View is a customizable view that will change based on your Data Management Ap-
plication’s code. In general, it is used to render the data from a single record in a logical
fashion.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 117
Chapter 4. Trying It Out
A Detail View may include some or all of the values from the record it is presenting, and
it may include values drawn from other tables. The interface used to present that data is
118 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Detail With Sublist View is a customizable view that will change based on your Data Man-
agement Application’s code. It is a combination of a Detail View on the top half of the
screen and a List View on the bottom half of the screen.
The Detail View on the top half of the screen follows all the same rules as a normal Detail
View. In addition, it can control the List View rendered below it. There may be an interactive
element within the Detail View that will cause the subordinate List View to redraw with
different values.
Graph View
Graph View is a customizable view that will change based on your Data Management Appli-
cation’s code. In general, it is a often specialized List View that creates a graphical rendering
of the data (such as a bar graph or pie chart). It may also be a specialized Detail View or
Custom View.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 119
Chapter 4. Trying It Out
A Graph View uses JavaScript libraries such as D3 to create visualizations of collected data
on the device. These will be rendered on demand using the data available, meaning that
120 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Map View
Map View is a partially customizable view that will change based on your Data Management
Application’s code. The top portion of the view is a List View representing the records in
the data table, and the bottom portion of the screen renders the records as geopoints on a
map using Google Maps.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 121
Chapter 4. Trying It Out
Points are added to the map based on their recorded latitude and longitude values. The map
can be navigated by pinching or widening to zoom in and out, or swipe around to move the
window (the same controls as the stand alone Google Maps).
When a point is selected in a Map View it will usually update the List View on the top
portion of the screen to select the same point, and possibly present more data about that
point.
Navigate View
Navigate View is similar to Map View, but the top portion is replaced with navigational
tools to aid in finding a location on the map in the real world. The bottom portion of the
screen still renders the records as geopoints on a map using Google Maps.
122 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
When a point on the map is selected, the navigation controls on the top portion of the screen
will update to guide you to the selected point.
• Compass shows you cardinal directions in addition to an arrow pointing at the navi-
gation point.
• Distance shows the distance between your GPS location and the navigation point.
• Heading shows the direction that you are facing.
• Bearing shows the angle between your heading and your navigation point.
• GPS Accuracy Spinner shows the GPS’s current accuracy estimate. It will change
color based on how good this accuracy is.
The Arrive button will return you to the screen that launched the Navigation View with
a success code. This may launch a follow up Survey or workflow to be performed at the
navigation point.
The Cancel button also returns you to the screen that launched the Navigation View, but
with a failure code. It indicates that the navigation point was not reached and it will not
trigger a follow up workflow.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 123
Chapter 4. Trying It Out
Custom View
Custom View is a completely customized view that is defined by your Data Management
Application’s code. There is no general pattern for Custom Views.
124 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Custom Views are arbitrary user interfaces built on top of web technologies and rendered in
Tables. They can be anything your organization needs to implement its custom workflow.
Note: Custom Views are not limited to displaying data. They can also be used to collect
or modify data. See the guide for editing data with custom views.
The view types that represent multiple records (Spreadsheet View, List View, Map View,
Navigate View) can be alternately chosen, depending on what the Deployment Architect has
configured in the table’s settings.
To change to another view type, tap the lined paper icon from the upper right:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 125
Chapter 4. Trying It Out
This will bring up a menu that lets you select your desired alternate view type.
126 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Tip: Graph View is a special case. You may have the lined paper icon available to you,
but it may only have Spreadsheet View as its alternative option, and may not have an option
to return to the Graph View. Usually pressing the back button from Spreadsheet View will
return you to the Graph View.
Graph Views also may not have the lined paper icon available at all if they are instead
mapped as a Detail View or a Custom View.
Note: Not all view types will always be available. For example, if the data set does not
contain geographic data, the Map View and Navigate View options will not be available.
Tables supports creating new rows and editing existing records and provides a variety of
methods to do so. These can be integrated into your Data Management Application’s work-
flow or accessed directly.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 127
Chapter 4. Trying It Out
Most data change options use Survey to create or update the record. These options will
launch Survey from the Table in question to directly edit the relevant record, and then
return control back to Tables where you left off. Which options are available depends on
which view type you are currently using.
The + button is available in any of the multi-record views: List View, Graph View, Map
View, and Navigate View. This button will launch the configured Survey form to create a
new record in the table currently being viewed. The example picture above shows the Tea
Houses List View from the ODK Tables: Sample Application. If the + is pressed it will
launch a Survey to create a new tea house in the table.
128 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
The pencil button is available in any of the single record views: Detail View and Detail With
Sublist View. Detail With Sublist View is considered a single record view as the Detail View
portion is considered the controlling view, and the List View below is subordinate.
If the pencil button is pressed, it will launch the configured Survey form to edit the record
currently be viewed. When the record has been updated and control returns to the calling
view, the new details should be rendered in that view.
Spreadsheet View
Spreadsheet View also offers methods to launch Survey to create or edit records. If you know
exactly the table or record you want to edit, this view may be the more direct option. You
can also use Color Rules to find records that require your attention and then edit them
directly.
• Creating a Record follows the same workflow as the other multirecord
views. Press the + button to create a new row in the data table and see it
in the Spreadsheet View.
• Editing a Record can be performed by long pressing on the desired row.
A pop up will open when the long press is released.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 129
Chapter 4. Trying It Out
Tables supports direct creation and updates to data in the database through JavaScript
API calls. These will be completely customized to your organization’s Data Management
Application and you may need to contact that person to find out how to use your particular
design.
For more information on how to edit data with these custom views, see Creating Customized
Web Views.
Syncing Data
130 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Warning: If a data table has any checkpoint saves (for example, caused by form
crashes), the data table will not be synchronized. Checkpoints must be resolved before
sync can proceed. The user must open a form on the problem table and either delete the
checkpoint or edit the checkpoint. If editing, after that is complete they must save is as
either incomplete or finalized. Once the checkpoints are eliminated, the user can initiate
another synchronization, and the data in this table will then be synchronized with the
information on the server.
• Prerequisites
– Required
– Recommended
• Table Manager
– Importing Data
– Exporting Data
– Table Properties
* General Settings
· Columns
* Display Settings
· Color Rules
* List View Settings
* Map View Settings
– Deleting Tables
• Setting Up a Form Development Environment
• Adding Your Own Tables
– Initialize from ODK Application Designer
• Creating Customized Web Views
– Custom Home Screen
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 131
Chapter 4. Trying It Out
Prerequisites
Required
To create an Data Management Application that uses ODK Tables, you will need the ODK
tools:
• ODK Services
• ODK Application Designer
• ODK Cloud Endpoints
As well as the third party apps:
• OI File Manager
If you have not installed Tables already, follow our guide for Installing ODK Tables
Recommended
We also recommend:
• ODK Survey
ODK Survey is not required, but Tables and Survey are built to seamlessly integrate and
support more robust Data Management Applications.
Table Manager
The Table Manager provides you with access to administer tables, import/export data,
modify their settings, or delete them altogether.
132 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
The Table Manager is the default home screen that is shown when you launch Tables, unless
you have a custom home screen configured. See instructions for Showing/Hiding the Custom
Home Screen.
This view lists every table on the device. If you tap on the name of a table, a Spreadsheet
View will launch and you can view or edit the contents of that table.
Importing Data
You can load data from a CSV directly into a table that has been defined on the device. To
learn how to add a table, see Adding Your Own Tables.
A CSV is a comma-separated values file. It is a common way to transport tabular data
between different programs. Microsoft Excel can save and open CSV files, as can Open
Office and a variety of other programs. Tables expects a certain format of the data in
order to import the data correctly: the first line must be the comma-separated list of column
names. The remaining lines must be the data for each of the corresponding columns.
For example, assume you wanted to load data into table of people’s names, with column
(field) names of Name and Age. In addition to those columns, your CSV file must also
specify the unique row id (instance id) for each data row (the _id column). You can also
specify the creator of the row, the time of creation, and other information. But, at a
minimum, the file should look like:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 133
Chapter 4. Trying It Out
_id,Name,Age
myUniqueIdforSam,Sam,27
134 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 135
Chapter 4. Trying It Out
The data will be read from the file and appended to your data table.
Warning: Prior to any deployment, you should sync your device to your server and
export the data table and copy the exported CSV file back on top of the simple CSV file
that you created above.
This ensures that the additional fields required by the ODK tools are properly populated
and that a server-managed revision number is added to the data rows so that all devices
will have the same internal ids for all of your data rows. This eliminates the possibility of
the tables.init mechanism introducing duplicate records and speeds the sync process
and minimizes the occurrence of conflicts across the devices when these devices first sync
to the server.
Warning: Specifying the values for the _id column is important. Otherwise, each
device, when it loads the CSV file, would assign different unique ids for each of the rows,
causing much duplication and confusion.
136 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Exporting Data
You can export any of your tables to a CSV file and associated supporting files. These files
will be written to the output/csv directory on the device.
A Tables-exported CSV includes all the metadata needed to allow the table to be imported
with exactly the same status settings, file associations and metadata settings on another
device. Exporting produces the following files:
• file:tableid.definition.csv – this defines the data table’s structure. It specifies the
columns and their column types and is a copy of the file found under config/tables/
tableId/
• file:tableid.properties.csv – this defines the column heading names, translations, and
the HTML files associated with List Views, Detail Views, Map Views, and so on, and
is a copy of the file found under config/tables/tableId/
• file:tableid.csv – this holds the data file that you can import to recreate the contents
of your data table
• file:tableId – this holds an instances folder that holds folders named after each row id
(the row id is cleaned up to remove any invalid filename characters such as slashes and
colons). Each of those folders contains the row-level attachments for that row id.
To export a table:
1. Launch ODK Tables and navigate to the Table Manager screen.
2. Press the arrow -> icon at the top of the Table Manager screen.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 137
Chapter 4. Trying It Out
138 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
4. Optionally specify a qualifier that will be inserted into the filenames of the
emitted files before the .csv extension.
5. Press Export.
For example, if you were to export the geotagger table and specified demo as a qualifier, the
following files would be written:
• output/csv/geotagger.demo.definition.csv
• output/csv/geotagger.demo.properties.csv
• output/csv/geotagger.demo.csv/geotagger.demo.csv
• output/csv/geotagger/instances/1f9e.../137...jpg
• output/csv/geotagger/instances/...
Table Properties
Table properties define a table and its behavior on the device. This includes basic necessities
such as the table’s ID and columns, references to sister files such as the forms to use when
adding new rows or the html file to use when rendering a List View, and display settings
such as map pin color rules and spreadsheet column width. Some of these properties are
defined in the Properties worksheet in the XLSX file.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 139
Chapter 4. Trying It Out
2. This will launch the Table actions pop up. Select Edit Table Properties
140 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 141
Chapter 4. Trying It Out
The table properties can also be accessed by tapping that same gear icon in the Spreadsheet
View of the desired table.
General Settings
The general settings define a table and are mostly not editable on the device. They include:
• Display Name: The string to display to as the name of the table, such as in the Table
Manager view.
• Table ID: The ID of the table, which is used when performing database queries.
• Columns: The full list of data columns in the database table.
Columns
Tapping the Columns item will launch a list of all the columns in the table.
Note: The columns list excludes the status and metadata columns that the
ODK-X platform automatically adds. It only shows the columns holding data
defined by the Deployment Architect.
142 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
If one of the columns is then selected, properties for that column can be set.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 143
Chapter 4. Trying It Out
– The next time you open Spreadsheet View for this table, the column width will
be updated.
144 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
• Edit Color Rules: This lets you set the color rules. See the color rules guide.
Display Settings
Display settings change how the table is presented to the user. They include:
• Change Default View Type: Allows you to change the default view presented when
a user selects a table. If selected this will display a pop with all available view types
to choose from. This is typically List View or Map View.
• Default Form: This is the form ID to launch in Survey when adding a new row.
• Edit Table Color Rules: This lets you set the color rules. See the color rules guide
below.
• Show Status Column Color Rules: If this is tapped it launches a screen that
details the status column colors and their meanings.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 145
Chapter 4. Trying It Out
Color Rules
Color rules allow you to modify the appearance of cells in Spreadsheet View based on the
values of the data in those cells. You can have a collection of color rules set for a table to
make visually scanning the spreadsheet much quicker and more informative.
To add a color rule:
1. Launch Table Properties and scroll down to select the Edit Table Color Rules
item.
146 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
2. This will launch the color rules page. Tap the + button in the upper right
to add a new color rule.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 147
Chapter 4. Trying It Out
3. Choose the Element Key or column that will be affected by this color rule.
4. Choose a Comparison Type and Value. Combined, these two fields determine
the equation to use when checking the color rule. For example, you might
have chosen an Element Key of Visits that tracks the number of visits to a
tea house. You might then choose a Comparison Type of < and a Value of
1000. This would apply the color rule to all tea houses with a visit value
that is less than 1000.
5. Choose the Text Color and Background Color to apply when this color rule
evaluates to true. In our above example, we might set the Backgroung Color
to red to highlight all the least popular tea houses.
6. Press Save.
To clear out the existing color rules, tap the trash can icon in the upper right.
The List View Settings determine which HTML files to use when this table is opened in a
List View or a Detail View. These are typically set in the XLSX file, but can be updated
here, or swapped between multiple options.
If this is not specified, the table will not be able to be opened in a List View or Detail View.
The Map View Settings determine which HTML file to use when this table is opened in a
Map View. This is used to render the List View at the top portion of the screen. This is
typically set in the XLSX file, but can be updated here.
If this is not specified, the table will not be able to be opened in a Map View.
These settings also contain the Color Rule For Map option. This lets you choose between:
• None: Uses the default blue color for map markers, and green for a selected map
marker.
• Table Color Rules: Uses color rules set up in the Color Rules screen to determine
the map marker (the same color as the Spreadsheet View cells.
• Status Column Color Rules: Uses the color of the status column as the color for
the map marker. This is useful to show which map items have had changes since the
last sync.
148 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Deleting Tables
The Table Manager allows you to delete a table off a device. However, this is generally
discouraged and should rarely be performed.
To delete the table:
1. Launch the Table Manager. Tap the gear icon next the desired table:
2. This will open the Table actions pop up. Select Delete this Table.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 149
Chapter 4. Trying It Out
3. You will then be shown a confirmation dialog. If you are sure, confirm, and
the table will be deleted and marked for the next synchronization.
To get started creating your own Data Management Applications, go to the ODK Application
Designer documentation.
The creation of data tables is handled within the ODK Application Designer. ODK Tables
can display and present data, but cannot create Tables on the fly. This enables the ODK
Services application to enforce that the configuration of the device (its tables, HTML files,
form definitions, and so on) are identical to those on the server.
See the documentation for Building an Application and Creating Web Files for more details
on adding your own tables and defining their properties.
150 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Instructions for creating your own custom web views for presenting and modifying data, and
implementing your custom workflow, go to the web view design guide.
For the convenience of Data Management Application developers, the ODK-X platform
provides a number of basic view types, such as List Views and Detail Views. These can be
used and extended in your applications, or you can create something completely unique to
your requirements with a custom view. Some of these views can be configured as defaults
in Table Properties, and you can also launch directly into them with JavaScript calls from
/system/tables/js/odkTables.js. Examples include:
• openDetailView to launch a Detail View, providing a query to select the desired record.
• openListView to launch a List View, providing a query to select the desired list of
records.
• openTableToMapView to launch a Map View with a similar query to openListView
• openDetailWithListView to launch a Detail With Sublist View. The JavaScript file for
the corresponding Detail View should then call setSubListView to fill in the bottom
portion of the Detail With Sublist View.
• And more for different view and query types
The above APIs generally take a query as a parameter, run it in the background, and have
the results available when the JavaScript file loads. These query results are retrieved with
the getViewData API available in /system/js/odkData.js. There are more APIs available
for reading, creating, updating, and deleting records in the odkData.js API. Some examples
include:
• query to read data from the database
• updateRow to modify a row in a table
• deleteRow to delete a row from the table
• addRow to create a new row to a table
• getAllTableIds to get a list of all defined tables
• getUsers to get a list of user accounts
• And more
Third party libraries, such as Math.js or Snap.js, can also be included.
Example code to explore these APIs and how they can be used (including the ODK Tables:
Sample Application) are available in the App Designer Github Repository.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 151
Chapter 4. Trying It Out
ODK Tables allows you to customize the app home screen. If you supply a custom home
screen (config/assets/index.html), you will have the option of using this as the home
screen of the app. For an example, see the sample application.
If you are installing Tables on a new device and don’t have a server set up from which to pull
the data (see the section about syncing, you can alternatively configure Tables to import data
at startup. This is useful during forms development, as you can push the form definitions,
HTML, and JavaScript for your application data down to the phone from your computer
and launch ODK Tables, and it will load data from CSV files into your data tables.
The configuration file must be titled tables.init and placed in the /sdcard/odk/tables/
config/assets directory. Below is the complete contents of the tables.init file distributed
with the sample application:
teaHouses.filename=config/assets/csv/Tea_houses.updated.csv
teaTypes.filename=config/assets/csv/Tea_types.updated.csv
teaInventory.filename=config/assets/csv/Tea_inventory.updated.csv
teaHousesEditable.filename=config/assets/csv/Tea_houses_editable.updated.csv
geotagger.filename=config/assets/csv/geotagger.updated.csv
plotVisits.filename=config/assets/csv/visit.example.csv
plot.filename=config/assets/csv/plot.example.csv
femaleClients.filename=config/assets/csv/femaleClients.allfields.csv
maleClients.filename=config/assets/csv/maleClients.allfields.csv
geopoints.filename=config/assets/csv/geopoints.allfields.csv
follow.filename=config/assets/csv/follow.updated.csv
The table_keys key contains a comma and space separated list of table keys. Each table
key can then have a .filename that indicate the filename of the CSV data that should be
imported. This file should be under the config/assets/csv directory and the name should
begin with the tableId, followed by an optional qualifier (for example, allfields), and end with
.csv. If there are row-level file attachments for the table, they would be placed in a tableId
file within the csv directory. Each row-level file attachment filename is relative to the
folder for that row’s id. If the rows _id column was myUniqueIdForSam, then the filenames
in the data table for row-level attachments for that row would be relative to /sdcard/
opendatakit/default/config/assets/csv/tableId/instances/myUniqueIdForSam/.
Note: Any table ids appearing in this file must already have their table definitions and
metadata values defined in the definition.csv and properties.csv files within their correspond-
152 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.5. ODK Tables
Tip: Only one attempt is made to read and import data at start-up. If that attempt fails,
some or all tables may not be initialized or may be partially initialized. You can trigger a
re-processing of this file by going to Settings and clicking Reset configuration then exiting
the ODK tool and re-opening it.
As mentioned earlier, this file is never uploaded to the server. After you have created your
user application and loaded data onto your device using this mechanism, resetting the app
server will push all the configuration files and all of data (the data rows loaded by the
tables.init script) up to the server (except for this tables.init file). Other devices
that synchronize with the server will retrieve all of those data rows during the data-row
synchronization phase. There is no need for the devices that synchronize with the server to
have a copy of the tables.init file and independently perform these actions.
The ODK-X tools are designed to support multiple independent Data Management Applica-
tions running on the Android device. Each of our tools has the ability to run in the context
of either a default application name, or a specified application name.
For further details on how to launch multiple AppNames and create your own new App-
Names, see Survey’s guide to Launching With a Different AppName.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 153
Chapter 4. Trying It Out
– assets – contains files that initialize your data tables (in the csv sub-folder) and
define the custom home screen and provides CSS files for overall appearance of
your app, and JavaScript libraries and files for common behaviors in your app.
– tables – contains directories that are named with table ids. Within these sub-
directories, the ODK Survey forms and table-specific HTML, JavaScript, and CSS
files are found. For example, the HTML file describing the list view for the tea
houses table is found in config/tables/Tea_houses/html/Tea_houses_list.
html.
• data – contains the database and row-level attachments (files).
• output – contains files that are generated (such as detailed logging files) or exported
(such as CSV files) by the ODK tools on the device.
• system – an area maintained by the tools themselves (ODK Survey, ODK Tables, ODK
Scan, and so on). These files are extracted and placed here by the APKs. You should
not modify files in this folder; when first started, the ODK tools sweep this directory
to verify that these files match their internal copy. Any deviant file is replaced with a
fresh internal copy.
The automatic configuring and loading of data into ODK Tables is governed by the config/
assets/tables.init file. It provides a list of table ids and the CSV files (located in the
config/assets/csv folder) that should be imported to populate them. This is discussed in
more detail in the Tables User Guide.
Note: This file is the only configuration file that is not synced to the server. This is to
optimize start-up of your application on other devices; once this initial data has been loaded
into your data tables and synced to the server, the other devices will obtain the data through
an ordinary sync action.
Note: This file is scanned once. If the import(s) fail, it could leave some tables partially
initialized. The file will be re-processed and data rows re-loaded by clicking on Reset Con-
figuration on the Settings screen then exiting the ODK Tools and re-launching them. Upon
being re-launched, the file will be scanned and processed.
Most of the app-level settings that are configured through the Settings page are stored in
the config/assets/app.properties file. Excluded from this file are the Server Sign-On
Credential type, and the values for that credential (such as username and password). This
allows the application designer to specify and enforce most of the app-level settings (such as
the server used when syncing) via the sync mechanism.
154 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
ODK Services is a program that handles database access, file access, and data synchroniza-
tion services between all the ODK-X applications. Mostly this happens behind the scenes,
but you will need to install ODK Services as a prerequisite to using the other ODK-X tools.
It also allows you to sync data collected by the ODK-X tools with an ODK Cloud Endpoint.
The Services application can be used to reset the Cloud Endpoint with the data that is on
a tablet or to sync the data on the tablet with what is currently on the Cloud Endpoint.
Prerequisites
Before installing ODK Services, you will need the following third party apps:
• OI File Manager
There are no other ODK Android tools that are prerequisites to installing ODK Services.
However, this tool is a prerequisite for all the other ODK-X Android tools.
Installing Services
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 155
Chapter 4. Trying It Out
Note: You can also download the ODK Services APK to your computer and load it on
your device via adb or another tool like AirDroid.
Tip: You can also install ODK Services on an Android emulator. However, this can be
slow and is only recommended for developers actively working on Services.
Before you are able to synchronize your data or application files, you will need to configure
your server settings. Instructions are provided in the deployment architect guide.
Authenticating Users
To log in or change the authenticated user, launch Services and open the user authentication
screen. There are two ways to do this:
• Launching From the Home-Screen: Press the Action Button (�) and select Change
User/Logout
156 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
• Launching From the Sync Screen: From within the Sync screen, press the Change
User button.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 157
Chapter 4. Trying It Out
Within this page you can enter a new username and password and click the Authenticate
New User button to contact the Cloud Endpoint and log in as this new user.
Note: To authenticate a new user, you must have a network connection and have the
Server URL set appropriately. See the deployment architect guide for instructions on how to
set this.
If you want to log out of your current user without logging into a new user, click the Log
Out button. This does not require a network connection.
Syncing
Use this option to submit your data and download the latest updates from the server. When
this process is finished, the data on your device and the server will match. You will also
receive any updates to your application that your Deployment Architect might have made.
There are two ways to launch the Sync screen.
• Launching From Services: Launch Services. Click the Sync icon that looks like two
arrows circling each other.
158 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
• Launching From Another Tool: From within Survey or Tables click the Sync icon
(same as above). This will launch Services to the Sync screen. Below this is shown in
ODK Survey.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 159
Chapter 4. Trying It Out
160 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
Before syncing, you should verify all options are set correctly.
1. The username can be be changed by pressing the Change User button.
Instructions are provided in the Authenticating Users section.
2. The sync interaction has four options for managing file attachments. These
are offered if bandwidth or storage is a concern:
• Fully Sync Attachments - Default - Synchronize all file attachments with the
server.
• Upload Attachments Only - Only upload attachments from the device to the
server.
• Download Attachments Only - Only download attachments from the server
to the device.
• Do Not Sync Attachments - Do not sync any attachments.
Note: All four of the attachment options will fully synchronize your database.
This includes all completed forms and collected data.
When you are ready to sync you data click on Sync Now.
Services will contact the Cloud Endpoint and synchronize your data. A progress dialog
will be displayed and, alternatively, the status of sync can be obtained by looking at the
notifications generated by Services in the notification area.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 161
Chapter 4. Trying It Out
Note: The sync will proceed whether or not you remain on this page and you can use the
back button to back out of it and return to your work.
Warning: Should you begin modifying data rows while syncing, the changes to those
rows will not be synced until you save them as incomplete or finalize the row, and the
act of editing will generally mark the sync as having ended with conflicts. This means
that you must complete your edits and re-issue the sync to ensure that your changes are
propagated up to the server.
When you return from ODK Services and next access data, the ODK-X tools will scan
all tables looking for conflicts arising from the synchronization process. If any conflicts are
found, you are required to resolve the conflict before proceeding to your activity. The options
for resolving conflicts are as follows.
• Take Local Version - Use the version on the device, deleting the server version.
• Take Server Version - Use the server version, deleting the version that is on the device.
162 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
• Merge Changes - Will be enabled once all conflicts in the row’s data fields have been
decided.
Choose the desired option. Once the changes are reconciled, you can then proceed to the
activity you were accessing and, when you next sync, the resolved conflicts and any new
changes will be pushed up to the server. Then, other users will receive those changes when
they sync to the server.
Device Settings
The device settings allow you to change configuration on your individual device. These
settings will not be synchronized with the server.
1. Open Services. Press the Action Button (�)
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 163
Chapter 4. Trying It Out
164 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
Tables Settings
The tables specific settings modify the behavior of the ODK Tables tool. These settings will
not be synchronized with the server.
1. Open Services. Press the Action Button (�)
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 165
Chapter 4. Trying It Out
• Use Custom Home Screen chooses whether to display the index.html file of
your Data Management Application or the list of tables when ODK Tables
166 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
is launched.
Troubleshooting
• If you are not seeing your forms in ODK Survey or your data tables in ODK Tables,
try Resetting Configuration
• If you are seeing a list of data tables instead of your Data Management Application
home screen when you launch ODK Tables, enable the Use custom home screen option
in Tables Settings.
• If you are having trouble syncing, check your Server Configuration.
• Prerequisites
– Compatible Servers
• Server Configuration
• Resetting the App Server
• Administrator Settings
– Setting an Administrator Password
– Accessing Administrator Settings
– Managing Server Settings
– Managing Tables Settings
– Managing Device Settings
– Locking Administrator Settings
• Resetting Configuration
Prerequisites
ODK Services is a prerequisite to all Data Management Application. You will also need the
ODK tools:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 167
Chapter 4. Trying It Out
Compatible Servers
It is important to match your version of ODK Services with an appropriate version of a ODK
Cloud Endpoints. To do this, find the release from the Services Releases page and match it
to a release from the Sync Endpoint Releases page. Or, if you want to use ODK Aggregate,
check the release notes for the appropriate version.
Server Configuration
Before you are able to synchronize data or application files to a device, you will need to
configure your server settings within Services. This tells the device which server to contact
and what user to authenticate. After these settings are configured, you can optionally lock
them with an administrator password. See Administrator Settings.
1. Open Services. Press the Action Button (�)
168 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 169
Chapter 4. Trying It Out
170 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 171
Chapter 4. Trying It Out
Resetting your app server pushes the configuration and data on your tablet up to the server.
After pushing files from ODK Application Designer to the device, this is how to push those
files to the server to initialize your Data Management Application. All other devices syn-
chronizing with your server will receive these configuration and data files.
Note: This option should only be used to initialize or update your Cloud Endpoint.
Warning: If a data table on the server does not exist on the device, that table, all of
its data, and all associated files (such as forms) will be deleted from the server.
If a data table on the server is identical to one on the device, the data in that table will be
synced and the files on the server will be updated to be exactly those present on the device
(deleting any files associated with this table that existed only on the server).
Before resetting:
172 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
1. It is critical that you first ensure that your device contains all the tables, files, and
data you want to preserve in your application. See instructions.
2. Authenticate as a user who has administrator privileges. See instructions.
To reset the server you must launch the Sync screen. Launch Services. Click the Sync icon.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 173
Chapter 4. Trying It Out
Before resetting, you should verify all options are set correctly.
1. The username can be be changed by pressing the Change User button. If
you do not see the Reset App Server button then you need to change users
to an administrator. Instructions are provided in the Authenticating Users
section.
2. The sync interaction has four options for managing file attachments. These
are offered if bandwidth or storage is a concern:
• Fully Sync Attachments - Default - Synchronize all file attachments with the
server.
• Upload Attachments Only - Only upload attachments from the device to the
174 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
server.
• Download Attachments Only - Only download attachments from the server
to the device.
• Do Not Sync Attachments - Do not sync any attachments.
Note: All four of the attachment options will fully synchronize your database.
This includes all completed forms and collected data.
Click on Reset App Server. A confirmation dialog will popup asking you to confirm resetting
the App Server. Again, this can delete all data on this Cloud Endpoint! If you are sure you
want to continue, click Reset.
Services will contact the ODK Cloud Endpoint and attempt to push all configuration and
data currently on the tablet up to the specified Cloud Endpoint. A progress dialog will be
displayed and, alternatively, the status of resetting the app server can be obtained by looking
at the notifications generated by Services in the notification area.
Note: The sync will proceed whether or not you remain on this page and you can use the
back button to back out of it and return to your work.
Warning: Should you begin modifying data rows while syncing, the changes to those
rows will not be synced until you save them as incomplete or finalize the row, and the
act of editing will generally mark the sync as having ended with conflicts. This means
that you must complete your edits and re-issue the sync to ensure that your changes are
propagated up to the server.
Administrator Settings
Administer settings allow you to lock in certain settings so that they cannot be changed
without the administrator password.
Tip: To modify a setting locked behind administrator privileges, enter the administrator
password and then access that setting.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 175
Chapter 4. Trying It Out
176 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
3. Select Admin Password. A prompt will appear where you can enter a new
admin password.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 177
Chapter 4. Trying It Out
4. After creating an admin password, the screen show show that it is enabled.
After the administrator password is set, you can enter it to access the administrator settings.
1. From the Settings screen, select Admin Access to Settings
178 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 179
Chapter 4. Trying It Out
3. After entering the correct password, you will see the full list of administrator
settings available to you.
180 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
Warning: This option should only be used for testing. When deployed
to the field you should always enable SSL encryption.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 181
Chapter 4. Trying It Out
• Use custom home screen - if checked the custom home screen option will be
locked.
182 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
• Text Font Size - if checked the text font size will be locked.
• Change Splash Screen settings - if checked the splash screen image and
enable/disable flag will be locked.
When you have finished configuring the administrator settings, back out of the menu. You
will then see the normal settings menu, but with all appropriate settings locked. To modify
these locked settings, follow the instructions for Accessing Administrator Settings and repeat
the process.
Resetting Configuration
This option will clear the ODK-X cache of table and form definitions and scan the file system
to refill that cache. This is automatically run after each successful sync operation to ensure
that Survey and Tables display the correct information. If you have manually modified files
inside of the /sdcard/opendatakit/ folder via grunt commands, with OI File Manager,
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 183
Chapter 4. Trying It Out
or by some other means, you may need to use this option to refresh the cache. If you are
not seeing forms or tables that you expect, this option may fix that problem.
Note: This option does NOT delete any data or files. It also does not reset your server
URL setting. But it will log you out of your currently authenticated user and clear your
device and tables settings.
After pressing this option, you will be prompted to confirm this is what you want to do.
Press OK to clear the config. Back out of the Settings menu. The next time you run Tables
or Survey they will rerun their initialization logic, which may take a few moments.
Sync Details
Syncing has two phases. In the first phase, data tables are created on the device that
correspond to the data tables on the server, and the form definitions and other files on your
device are made to exactly match those available on the server (updating them as needed).
184 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.6. ODK Services
Warning: If a data table on the device does not exist on the server, the configuration
files and all associated forms for that table will be removed from the device. To prevent
data loss, the table itself will not be deleted, but, by removing all of the configuration
files for that table, the data will generally be unusable.
In the second phase, it synchronizes the contents of the local data tables with the contents
on the server, including any row-level file attachments associated with individual records in
the data table. Row-level file attachments are bundled and synced one row at a time.
Unlike ODK Collect, where individual forms can be added and removed at will, ODK Services
and the ODK-X tools are organized Data Management Applications consisting of a set of
interrelated data tables and forms. All the forms and tables on the server collectively define
the Data Management Application* and ODK Services ensures that the device conforms to
that Data Management Application definition. You can operate multiple independent Data
Management Applications on a single device by placing their files and forms under different
application folders within the /sdcard/opendatakit/ folder. Each such application will
publish to a different ODK Cloud Endpoint. This is a significant and powerful change from
the ODK mindset.
Database Details
ODK-X data is stored in a SQLite Database running on the Android device. After a device
synchronizes with the server, this database will fully match the schema and contents of the
database running in the ODK Cloud Endpoints.
Each Survey form instance will write to a row in the database. However, this mapping is
not one-to-one: the form may not fill the entire row’s columns and another form might fill
other fields in the same row. Furthermore, sub-forms allow you to launch forms that write
to other database rows. See ODK Application Designer and ODK Survey for more details.
Data tables and schema can also be created manually and used as a back-end for your Data
Management Application using ODK Tables.
At any point you can copy the local database on the Android device onto your desktop
computer and inspect its contents and schema. If your application name is default then the
database is stored in:
/sdcard/opendatakit/default/data/webDb
To inspect the database, use the adb pull command (Google documentation is available
here). Then use a program such as DB Browser for SQLite to view the database. Further
instructions are available in the Pushing and Pulling Files guide.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 185
Chapter 4. Trying It Out
Warning: ODK Scan is not yet fully released! It is not guaranteed to work at the same
quality level as ODK Survey, Tables, Services, or the rest of the release ODK-X tools.
It is currently at the Beta stage, which mean it does not have all features, but is not likely
to have significant reductions or alterations in functionality. Beta releases are provided
to gather user feedback on the usability and capabilities of the application, as well as
bug reports (to make the application more robust). Updates may result in loss of data
or incompatible changes in form designs.
ODK Scan is an Android application that uses the device’s camera and specialized code to
automatically digitize written data from paper forms. Using the app, users take pictures of
paper forms and ODK Scan detects and collects the fill-in bubble, checkbox, and written
number data. It also saves image snippets of handwritten text and displays them on the
screen for easy data entry. The digitized data can then be validated, exported, saved into
a database, and used for custom data reports. This workflow from paper form to digital
database occurs in five processes and is supported through the use of ODK suite tool
186 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.7. ODK Scan
Prerequisites
Before installing ODK Scan, you will need the following ODK Tools:
• ODK Services
• ODK Survey
• ODK Tables
As well as the following third party apps:
• OI File Manager
Installing Scan
Warning: ODK Scan is only compatible with Android versions 4.4 or newer.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 187
Chapter 4. Trying It Out
Note: You can also download the ODK Scan APK to your computer and load it on your
device via adb or another tool like AirDroid.
Note: To synchronize your data with the cloud you will also need ODK Cloud Endpoints.
Note: Before scanning you’ll first need to create printable form template using the ODK
Scan Form Designer.
• Scanning a Form
– Prior to scanning
– Scanning the form
• Survey: View, Verify, & Edit Data
– Reviewing Your Data
– To verify and edit any of the data
– Saving and Finalizing Changes
• Your Data in Tables
Scanning a Form
Prior to scanning
Have a printed form ready. For more information on printing the form created in Form
Designer see the printing instructions.
Open the Scan app, and be sure that the template you want to use this session is selected
in the settings. Go to Settings → Templates to Use, make sure the correct form is selected,
and click OK.
188 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.7. ODK Scan
1. When you are ready to begin scanning, click Scan New Form from the main
page in Scan. This will bring up a camera window.
2. Adjust your positioning until there is a good view of the form in the
viewfinder. When you are ready to take the picture, tap the camera
icon.
• The form should take up 80% of the photo area.
• Make sure that the form is lying as flat as possible so that there
will be no curvature in the form.
• Tap anywhere in the viewfinder to focus the camera.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 189
Chapter 4. Trying It Out
3. If the preview of the photo looks good, tap the checkbox icon to move onto
the next step. To retake the photo tap the Back button and to exit the
camera tap the X.
4. Once you select the check mark to begin photo processing, a small message
will pop up saying Processing photo in background.
5. When the photo has been successfully (or unsuccessfully) processed, you
will see a notification at the top of the screen in the Android toolbar. Pull
the top toolbar down and tap the ODK Scan notification. This will open
Scan and pull up the photo of the selected scan.
• The successfully processed photo will show an overlay of colored
boxes that indicate the fields that Scan has detected. Any bubbles
or checkboxes recognized as filled will show an overlay of the value
that was assigned to them in the form designer. Number fields will
show an overlay of the number that the app recognized for each
digit.
• If the photo was unsuccessfully processed you will be prompted to
retake the photo.
190 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.7. ODK Scan
6. From this screen, you can choose to either begin reviewing the data from
this scan, or save it to review later. Press Transcribe to be taken into ODK
Survey where you will be able to view and edit data.
• Or press Save. This scan is now accessible by tapping the drop down options
(at the top right of the screen), then Main Menu → View Scanned Forms).
From the drop down options, you can select Scan New Form to continue
scanning and saving forms.
Tip: To increase accuracy of Scan’s results, you can consider building a stand with a clear
plastic surface to place your phone or tablet on top off while you take the each photo. The
stability can help improve the alignment and reduce blur in photos. Below is an example of
a stand built with PVC piping and Plexiglass.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 191
Chapter 4. Trying It Out
You’ll be taken to Survey after pressing Transcribe on a scan. There you’ll see a clickable
list of all of the fields pulled from your form template, your Table of Contents. You can
return to this screen when transcribing data by pressing the button on the top, left (with
your form template’s name, the example image below being scan_TB03_Register1).
192 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.7. ODK Scan
Select the field you want to view, and you’ll be taken to a screen where you’ll find an image
of the field and the data, as interpreted by Scan, and an editable box below. Type in any
changes if there are discrepancies between the data digitized by Scan and the ground truth
data.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 193
Chapter 4. Trying It Out
194 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.7. ODK Scan
Note: The order that these fields are presented can be set when originally creating the
form template in Form Designer. With a data field selected, in Form Properties enter a
numbered order (for example: 1, 2, 3, and so on) in Order of Fields.
Note: Text boxes and text fields cannot be digitized. However, Scan will capture an image
of text boxes (not text fields: text fields are to be used primarily as labels on your form),
and when verifying data in Survey you can type in the data directly into the app.
You have the option of saving changes you’ve made to the data and returning to it later to
further review. Go to the Form Name → Save Changes + Exit. You can access this scan’s
data again from Scan> → View Scanned Forms. They will be arrange in the chronological
order they were originally scanned.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 195
Chapter 4. Trying It Out
If you’ve made changes you don’t want to keep, Form Name → Ignore Changes + Exit.
Once you’ve verified all the fields, select Form Name → Finalize Changes + Exit. You will
also have the option to Finalize Changes if you are navigating through the data fields by
using the next button and reach the end of the data contents. Once you are finished here
you will return to Scan, where you can scan a new form or transcribe a saved scan. Both
options accessible through navigating to Scan’s Main Menu.
With each verified and finalized scan, a new line of data will be entered into Tables. To view
(on your device) the verified data collected in this instance: open the Tables app and select
the line with your form’s name listed. This will open up a spreadsheet of your data. If you
need to need to edit the data in a record from here:
1. Double tap on the cell you want to edit.
2. You’ll be given the option to either Edit or Delete that row. Choosing Edit will launch
the form in Survey.
3. You can change the View Type, Color Settings, and more by pressing the settings wheel
and making any changes you need.
196 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.7. ODK Scan
• Prerequisites
• Transferring a Form Template to the App
Prerequisites
To create an Data Management Application that uses ODK Scan, you will need the ODK
tools:
• ODK Services
• ODK Survey
• ODK Tables
• ODK Application Designer
• ODK Cloud Endpoints
As well as the third party apps:
• OI File Manager
If you have not installed Scan already, follow our guide for Installing ODK Scan
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 197
Chapter 4. Trying It Out
ODK Scan works with machine readable forms created using the ODK Scan Form Designer.
Refer to the Using ODK Scan Form Designer for instructions on how to create these forms.
After creating a form with Form Designer, you’ll have generated the machine readable files.
To push them to your device, you will use the same mechanism that is used to push Survey
and Tables files to the device.
1. Create a form using the ODK Scan Form Designer. Save that form with the Save to
File System option.
2. Follow the instructions in Moving Files To The Device to push updates to the device.
These describe pushing Survey files, but they will push Scan files to the device too
with the same procedure.
3. To confirm that the [your_form] template has been successfully been transferred, open
the ODK Scan app on your device and go to Settings (the wheel icon) and select
Templates to Use. The folder name should appear in the list of templates.
ODK Scan shares a database with the rest of the ODK tools, and the data can be accessed
using the normal means through the ODK Cloud Endpoints and ODK Suitcase. However,
198 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Scan adds extra columns to store snippets of each data field’s original image, the image file
type, and the data value predicted by Scan.
Suitcase Formatting
ODK Suitcase is the mechanism for downloading and exporting data from the ODK-X data
tables into local .csv files. Suitcase has a specific option to format Scan’s .csv files more
to be more readable. The image below shows this option underlined in red.
ODK Application Designer is a tool to help you design data management applications on
top of the ODK-X framework. It works in conjunction with Excel or OpenOffice for form
design, the Chrome browser for rendering, and your favorite editor for template design.
In the context of the ODK-X tools, application design consists of:
• designing the forms used in data collection (by ODK Survey)
• designing the HTML landing pages and screens used for navigating, curating, and
visualizing that data on your Android device (within ODK Tables).
• customizing the look-and-feel of both of these via customized images, logos, and CSS
rules.
• designing mark-sense forms for paper-based data entry (by ODK Scan)
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 199
Chapter 4. Trying It Out
Tip: The tools operate independently – you are not required to use all the tools, or even
install them on your device. If you are only interested in data collection, you may only want
ODK Survey. Or if you are only interested in data dissemination and visualization, you
might only want ODK Tables.
Simply select the combination or individual tool that fits your needs. However, all of these
tools require ODK Services to access the database, sync to a server, and vend HTML files.
You must install the following software on your computer in order to use Application De-
signer:
• - Java is required by the Android SDK
• - Google’s Chrome browser.
• - a framework for easily building fast, scalable applications. Download Version 6.2.2
or higher and install it from NodeJS
• - a task-based scripting environment (installation is described below).
200 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
• - the software development kit for Android devices (installation is described below).
Warning: It is tricky to foresee all the issues that can crop up on many different
machines and setups. If something in this process does not go as expected, please check
the ODK Forum.
Warning: Android Studio is not supported on the Windows Linux subsystem, so you
will not be able to run Application Designer if you are using it.
Java
Make sure Java 7 or higher is installed on the computer you plan to use. If it is not,
download and install it. If you are using MacOSX, it may require special care and attention.
See MacOSX Java install and MacOSX Java FAQ.
NodeJS
You must use Version 6.2.2 or higher. To avoid directory path problems on Windows, we
require npm version 3, and that is only available on this node release (or higher). Follow the
instructions to install NodeJS.
For Windows
After installing NodeJS, ensure the location of the npm folder is added to the PATH vari-
able of your system. If it is not, subsequent calls to access grunt will fail. For example:
C:\Users\[username]\AppData\Roaming\npm. For instructions on modifying PATH, see
the section at the bottom of this page called Add adb to your PATH For Windows. Instead
of navigating to the location of Android SDK, navigate to the location of the npm folder.
For Mac/Unix
After installing NodeJS, open a terminal (which you can do by clicking the spotlight in the
top right corner of the screen, typing terminal, and clicking the program named Terminal)
and type:
$ npm --version
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 201
Chapter 4. Trying It Out
Warning: If a number is not displayed, but you instead receive a message that the
command npm cannot be found, you will have to perform some additional configuration.
As of this writing, by default NodeJS installs its commands into /usr/local/bin/. In
the terminal, type:
$ ls /usr/local/bin/npm
If this command outputs something like /usr/local/bin/npm, but you are still unable
to run:
$ npm --version
try running:
$ /usr/local/bin/npm --version
If this is successful, then npm is successfully installed, and you will just have to add
/usr/local/bin/ to your system PATH variable (see below).
If the command:
$ ls /usr/local/bin/npm
outputs a message telling you permission is denied, then you will have to change the
ownership of the /usr/local/ and /usr/local/bin/ directories. On Mac, follow the
instructions to take ownership of these directories, or to at least give yourself read permis-
sion. On other Unix systems, use the chown command or the user-interface appropriate
to your distribution to do so.
Grunt
Note: These installation steps are copied from the Grunt Getting Started guide.
On Windows, open a cmd window (go to Start Menu, search for cmd and open it); on
MacOSX, open a terminal window. Within this window, type:
If the above command is unsuccessful, some machines may need to append sudo at the
beginning of the command. If grunt is successfully installed, the following command:
$ grunt --version
Should display the installed version of grunt. For example the version might be grunt-cli
202 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
v1.2.0
Warning: If grunt is not found, you may need to add it to the PATH variable of your
system.
Android SDK
Note: You can alternatively install the full Android Studio if you so wish, in
which case you should follow Google’s instructions and then skip to step 6 of this
guide.
3. Within that section, download the appropriate file(s) based on your operat-
ing system.
4. Accept the license agreement
5. Wait for the install of the SDK Tools to complete. Windows will need to
manually run the .exe file previously downloaded to start installation.
6. Run the SDK Manager
• On Windows, it is available in the Start Menu under Android SDK Tools
Warning: If the packages fail to install, you may need to run the
Android SDK as an Administrator.
• On Mac/Unix, open the SDK folder you downloaded above. In the bin/ or
tools/ directories (on some versions it is in both places–it doesn’t matter
which you use), double click the file called android.
7. Select the latest versions of the following packages (by checking their check-
boxes):
• Android SDK Tools
• Android Platform-tools
• Android Build-tools
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 203
Chapter 4. Trying It Out
8. If extra packages are selected, you may unselect them before installation.
9. Click Install 3 packages in the lower right corner of the screen.
10. A licensing pop-up dialog will appear. Accept the license agreement(s) by
selecting the Accept License option. If there are multiple licenses, you may
need to select each license in the Packages window on this dialog and check
this Accept License option for each of them before the Install button will
become enabled.
11. Click the Install button on that dialog to begin the installation process.
Among many other things, this will install the Android Debug Bridge software on your
computer. This tool enables the scripted pushing of files and APKs down to your Android
device. See adb (Android Debug Bridge) for a listing of its capabilities.
Next, on Windows open a cmd window (open the Start menu, type cmd in the search box,
select and open it), and on Mac/Unix open a terminal window. Type:
$ adb version
If this displays a version string, then your installation is complete; you are done with this
section and can move on to Installing Application Designer.
Warning: If there is an error complaining about Java not being installed, you will need
to close this cmd or terminal window and download and install Java. After installing
Java, open a new cmd or terminal window and type this command again.
Warning: If adb is not found, then you need to add it to the PATH variable of your
system.
For Windows
1. Open a Windows File Explorer and navigate to the location of your Android SDK. This
will typically be at one of: C:\Users\your_username\android-sdks or C:\Program
Files\Android\android-sdk or C:\Program Files (x86)\Android\android-sdk.
2. Navigate into the platform-tools folder.
3. Click in the file path at the top of the File Explorer window. The path will become a
selected text string. Copy it into your copy-and-paste buffer.
204 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
$ adb version
You should now see the version of the adb tool. For example: Android Debug Bridge
version 1.0.31. You can now move on to Installing Application Designer.
For Mac/Unix
The PATH variable is nothing more than a default list of places the system looks for com-
mands. Open a terminal. Type:
$ echo $PATH
You will see a colon-separated list of folders on your computer. (echo means just print
whatever comes next, and the ${ } means that the system will treat PATH as a variable,
not a program. You don’t need to know this to follow these instructions, but knowledge is
power.) For example, you might see something like this:
$ echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin:/bin
$ adb --version
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 205
Chapter 4. Trying It Out
the system will look for the command called adb in the directories /usr/local/bin/, /usr/
local/sbin/, /usr/bin/, and /bin/.
Note the location where you downloaded the Android SDK. It should contain a folder called
platform-tools, which itself contains the program adb. If this was in the folder /Users/
someuser/Desktop/android-sdk/ you should be able to run:
$ /Users/someuser/Desktop/android-sdk/platform-tools/adb --version
This works because we’re telling the computer exactly where the program adb exists. By
putting the platform-tools directory on the system’s PATH variable, we will be able to
just type adb and have the system find it in the /Users/someuser/Desktop/android-sdk/
platform-tools/ directory.
This process is more involved on Mac/Unix than on Windows. Use a text editor (not Word,
but something like TextEdit), select the option to open a file, and browse to your home
directory. You can find your home directory by typing:
$ echo ~
in a terminal. (’~’ is a shortcut for the home directory.) Macs use a hidden file called
.bash_profile in the home directory to set variables like PATH. Other Unix systems use
files like .bashrc. You might have to check the specifics for your distribution to know which
you should use. Open the appropriate file. If the file does not already exist, create a new
file that will be saved with the appropriate name in your home directory.
We want to add the location of the adb tool to your PATH while preserving the existing
PATH information. Assuming that your adb program is in the /Users/someuser/Desktop/
android-sdk/platform-tools/ directory, you would add the following command to the end
of the .bash_profile file:
$ export PATH=${PATH}:/Users/someuser/Desktop/android-sdk/platform-tools
Save the file, close the terminal window, open a new terminal window, and type:
$ echo $PATH
You should see your old path with the new directory you added above, and you should now
be able to run:
$ adb --version
Tip: If you are going to be heavily customizing the look-and-feel of the application with a
lot of external JavaScript libraries, you might also choose to install bower.
206 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
$ grunt
This command runs the script contained in Gruntfile.js, so be sure it is in the current
directory.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 207
Chapter 4. Trying It Out
Terminal will open a new terminal window if you drag a folder (or pathname) onto the
Terminal application icon, and you can also drag a folder to the tab bar of an existing
window to create a new tab in that folder.
You have now completed the installation of the ODK Application Designer software.
This section presents a brief overview of the features of the ODK Application Designer.
The ODK Application Designer is accessed through a Chrome browser. Once launched, it
opens Chrome to display:
208 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Preview
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 209
Chapter 4. Trying It Out
You can navigate through forms, enter and exit sub-forms, and save results just like on your
Android device.
Note: The development environment does not allow you to submit data to a server. ODK
Deploy (currently under development, not yet released) will provide this functionality.
Customize
The Customize tab contains the CSS style and theme generator:
210 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Using this tool, you can change background colors, fonts, and other settings affecting the
appearance of a form. The changes are reflected immediately in the form shown to the left
of the toolbar.
This functionality is under active development and not currently recommended.
XLSX Converter
The XLSX Converter tab contains the conversion tool that transforms XLSX files produced
by Excel or OpenOffice into the formDef.json file used by ODK Survey:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 211
Chapter 4. Trying It Out
See ODK XLSX Converter documentation for more information about this tool.
File Browser
The File Browser tab provides a view into what will become the application’s directory on
the phone.
212 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
The Scan Form Designer tab presents a drag-and-drop editor for mark-sense form creation.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 213
Chapter 4. Trying It Out
See ODK Scan Form Designer documentation for more information about this tool.
Tip: We recommend unzipping and creating a new Application Designer directory for
each new set of ODK Survey forms, ODK Scan forms, and ODK Tables files that are not
intended to be deployed as a cohesive unit. If you need to have several of these sets of forms
and files co-resident on the same Android device, you would create different application
names for each set. The standard set up uses the default application name (appropriately
entitled default). To create a new application name, create a folder with that name next
to your default app and make sure it is stored on the device in the opendatakit folder. The
underlying ODK-X tools will then keep each of these sets of forms and files isolated from
each other.
214 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
To launch the application designer, open the cmd shortcut or Terminal window onto the
directory containing Gruntfile.js (the unzipped ODK Application Designer directory)
and type:
$ grunt
This should automatically open Chrome and display the Preview tab. When you need to
stop the server, return to the cmd or terminal window where you typed the grunt command
and press Ctrl+c. This will stop the process.
Warning: If you have Parallels or other virtualization software running, it might try
to open Chrome in this system by default. If so, you should still be able to navigate to
http://localhost:8000/index.html.
Warning: If the Chrome browser does not open, try opening it yourself and browsing
to http://localhost:8000/index.html.
Warning: If the page never times-out, but never loads (it remains blank or constantly
spinning), then stop grunt and try this command instead:
$ grunt --verbose connect:livereload:keepalive
This will start grunt, but disable the file-change detection mechanisms that automatically
reload an HTML page when it or any JavaScript file it uses has been modified. Others
have reported that uninstalling npm and node, and then re-installing them may correct
the issue.
There are many folders and files within the Application Designer directory. Fortunately,
the only ones that are of interest for a non-software-developer are:
• app/ - folder containing everything that will be pushed to the Android device.
• Gruntfile.js - contains the definitions of tasks that push files to the Android device,
launch the Chrome browser, and pull data and log files off the Android device.
Initially, you will only be concerned with the contents of your app/ directory – the set of
files that are placed on the Android device. As your sophistication grows, you may want
to define your own grunt tasks to automate repetitive steps in your deployment and device
management processes. Adding or modifying tasks is beyond the scope of this document;
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 215
Chapter 4. Trying It Out
please refer to the grunt website (see Getting Started Deployment Architect Guide for the
link to that site).
For completeness, here is the full list of the files and sub-folder in this directory. Again, you
generally do not need to be concerned with the contents or specifics of any of these:
• app/ - folder containing everything that will be pushed to the Android device.
• devEnv/ - contains the HTML for the 6 tabs of the Application Designer.
• grunttemplates/ - contains template files used by grunt tasks.
• node_modules/ - contains additional software installed by npm, such as external tools
used by grunt.
• scanFormDesigner/ - contains the Scan Form Designer tool.
• test/ - contains tests of the computer-based simulated device environment.
• themeGenerator/ - contains the HTML and JavaScript for the ODK ThemeGenerator
CSS style and theme customization tool (accessed via the Customize tab).
• xlsxconverter/ - contains the HTML and JavaScript for the ODK XLSX Converter
tool that converts XLSX form definitions into formDef.json files (accessed via the
XLSX Converter tab).
• .bowerrc - JSON configuration for the bower tool.
• .editorconfig - when your text editors are configured to use it, enables consistent
formatting to files across all contributors to your application design. See EditorConfig.
• .hgignore - source code management configuration.
• .hgtags - source code management configuration.
• .jshintrc - configuration for JSHint - a program that flags suspicious usage in pro-
grams written in JavaScript.
• bower.json - used to control library management through bower. By default, the
.bowerrc file has been configured to install these libraries in app/framework/libs/
so that you have access to them when your app is pushed to the phone.
• deleteDefAndProp.sh - MacOSX shell script to traverse the relevant parts of the app/
directory and delete the definition.csv and properties.csv files.
• Gruntfile.js - contains the definitions of tasks that push files to the Android device,
launch the Chrome browser, and pull data and log files off the Android device.
• index.html - the main HTML for the ODK Application Designer web page.
• macGenConverter.js - MacOSX command-line wrapper for the XLSX Converter tool
(converts a single XLSX file piped into stdin into a formDef.json on stdOut).
• macGenFormDef.sh - MacOSX shell script to traverse relevant parts of the app/ direc-
tory and generate formDef.json files from XLSX files.
216 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Everything in this folder mimics what is on the Android device. The directory looks as
follows:
• config - user-defined configuration for your application.
• data - file attachments, and, on the device, the database.
• output - on the device, logging files and exported CSV and media files.
• system - files managed by the ODK tools (do not modify).
This folder is synced to the device. It contains all of the form and table configuration files
and initialization scripts. This is the sub-folder in which you will be primarily working.
This folder contains:
• assets
• tables
• css/ - contains the common CSS files for ODK Tables detail, list and home screens,
and for app forms in ODK Survey (odk_survey.css).
• csv/ - contains the data files to be initially read and loaded into the ODK Survey and
Tables databases.
• fonts/ - contains the fonts used throughout the application.
• framework/ - contains the framework.xlsx and other relevant framework files.
• img/ - contains the images used throughout the application.
• js/ - contains JavaScript used by the ODK Tables custom home screen and/or the
ODK Survey custom forms list
• libs/ - contains the various libraries used throughout the application like jQuery and
D3.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 217
Chapter 4. Trying It Out
• tables.init - contains the initialization directives for which data (CSV) files should
be loaded at initial start-up of the ODK tools.
• index.html - the HTML for the ODK Tables custom home screen, if it is enabled in
the ODK Tables configuration settings.
This folder has a predefined directory structure, but the content is entirely dependent upon
the needs of your application.
The zip file for the ODK Application Designer populates this with all the subfolders used
by each of the ODK Tables and the ODK Survey demonstration zip files. Ultimately, when
you have completed your application design, this folder will contain none of these original
folders but would instead contain only the folders which you have created.
Note: Unlike ODK Collect, which stores each submission in a separate file, ODK Survey
and ODK Tables store their combined collected submission data in data tables (one row per
submission).
ODK Tables can display the contents of a table through one or more custom list views; it can
display individual submissions through one or more custom detail views. Graphical views
are simply list views in which the data is presented graphically using a library such as D3.
All of these custom views are defined here.
ODK Survey, unlike ODK Collect, has the additional flexibility of supporting multiple forms
to create, access and update data within a single common data table. This enables creating
multi-stage workflows such as initial screenings and follow-ups, or registrations and status-
updates (submission data can be editable, or not, based upon the form used at that workflow
stage).
To accommodate these various capabilities, the tables directory is structured such that
individual data tables each have their own directory within the tables directory. The
table’s table_id is the name of this sub-directory. When defining a new data table, begin
with a form whose form id is the table id.
218 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
view type of the table, etc. Generated when the form_id XLSX file underneath this
table_id is processed by the XLSX Converter.
• forms/ - contains directories for each ODK Survey form that manipulates this table.
The names of these sub-directories are the form_id values of those forms. Within
each sub-directory, there is a form_id.xlsx file defining the ODK Survey form and
the formDef.json generated by the XLSX Converter when it processed that form
definition file. If the form has form-specific images or media files, custom CSS, layouts,
or prompt types, those files should reside within the form’s sub-directory (nested sub-
folders are permitted).
• html/ the custom HTML files for the ODK Tables list and details views of the table’s
contents.
• css/ - contains CSS files specific to this table.
• js/ the JavaScript files needed for the custom ODK Tables HTML list and detail views
(found in the html/ directory).
ODK Scan is currently split in where it stores its configuration for mark-sense forms. The
current location for the ODK Scan templates is under app/config/scan/form_templates
directory. This will likely change and lead to additional sub-directories here.
The ODK Application Designer stores user data in this directory. The database itself is in
the webDb directory. Any data files associated with a row in the database are stored within
this folder under the tables/<table-id>/instances directory.
The ODK Application Designer provides various grunt tasks to pull files off the Android
device. These files include JSON objects for debugging, exported CSVs, and the database
itself. The grunt tasks store these files here. There is also a logging directory which contains
logs that are useful for debugging issues.
This folder contains the files that the ODK tools depend upon and which are expected to
be changed only when different versions of the ODK APKs are released.
Warning: Files in this folder are managed by the ODK tools. If you change any of
these files, the tools may detect the change and restore the file when they next start. The
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 219
Chapter 4. Trying It Out
goal is that only the ODK core team should have to modify things in this folder. If you
feel you need to modify anything in this directory, please contact us.
ODK XLSX Converter is a tool, similar to XLSForm, that converts XLSX files (created with
Excel) into ODK Survey definition files that are used by ODK Survey.
Warning: Forms created with XLSX Converter are not compatible with ODK Collect.
They only work with ODK Survey.
220 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
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. This
guide is designed to help you take advantage of this via a guided tour of example tasks.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 221
Chapter 4. Trying It Out
• Using Queries
– Linked Tables
• Internationalization
• More Advanced Branching
• Creating a Custom Initial Worksheet
• Using Validate
• Customizing Prompts
• Other Features
Tip: For a full reference to all the functionality available, see the ODK XLSX Converter
Reference.
Below are the steps to create a new form from the exampleForm:
1. Within the Application Designer’s folder, create the following directory
structure app/config/tables/your_table_id/forms/your_table_id/
2. Copy the exampleForm.xlsx from app/config/tables/exampleForm/
forms/exampleForm/ into this new directory.
3. Rename the XLSX file to your_table_id.xlsx
4. Edit the XLSX file and on the settings worksheet, change the value for
table_id to your_table_id. Then update the display title for the survey
and the form version. Save the changes.
5. If you have not already, run grunt to launch the Chrome browser and open
the Application Designer home page.
6. Navigate to the XLSX Converter tab, choose this file to convert it. Once
converted, choose Save to File System and click OK on the 3 pop-ups that
alert you to the saving of 3 files to the file system. The three files that are
saved are:
• app/config/tables/your_table_id/definition.csv – defines the user-
defined columns in your table
• app/config/tables/your_table_id/properties.csv – defines the ap-
pearance and available detail and list view HTML files for the table
222 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
• app/config/tables/your_table_id/forms/your_table_id/formDef.
json – defines the ODK Survey form defined by the XLSX file
7. The first two files are written only if the form id matches the table id. That
form and the XLSX file define the data table.
8. Repeat the edit, conversion, and save steps to update the columns in your
table and your survey form.
9. Connect your device to your computer with a USB cable.
10. In a separate command window, navigate to the Application Designer direc-
tory and type:
$ grunt adbpush
Typing the following in the survey worksheet of a workbook with an appropriate settings
worksheet will result in a simple survey.
The first row contains an empty clause and an empty condition column. Therefore, the
display.prompt.text will be shown on the screen, and the resulting integer answer will be
stored in the variable person_age.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 223
Chapter 4. Trying It Out
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.
Note: 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.
There are three types of multiple choice questions supported by ODK Survey:
• select_one
• select_one_with_other
• select_multiple
Multiple choice questions use the values_list column in the survey worksheet. The val-
ues_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 op-
tions.The resulting survey worksheet would look like this:
224 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
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.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 225
Chapter 4. Trying It Out
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:
Tip: When splitting a survey into different sections, it is wise to put a note before each sec-
tion call with display.prompt.text set to read 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
Note: The calculation column can store any valid JavaScript expression.
Tip: There are also some built in functions for ODK Survey that can be used anywhere in
the workbook. See the Forumla Functions for more details.
226 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
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:
Using Queries
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 227
Chapter 4. Trying It Out
• uri
• callback
For linked_table queries, these columns should be used:
• query_name
• query_type
• linked_table_id
• linked_form_id
• selection
• selectionArgs
• orderBy
• 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:
228 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
_.chain(context).pluck(’region’).uniq
return
{data_value:region,
display:{title:
{text: region}
} };
}).value()
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:
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.prompt.text fields using JavaScript. The survey
worksheets may look like this:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 229
Chapter 4. Trying It Out
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 Tables
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 infor-
mation 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:
230 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
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 instanceID of 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 via the newRowInitialElementKeyToValueMap content,
which specifies that the house_id field in the linked table should be initialized with the
instanceID of the current household.
Note: The selection criteria and its type (in this case, house_id and text) must be added
to the model subset of the subform (members_info) in order for selection criteria to be
persisted to the database and for the subform to be found by its parent form; the selection
criteria cannot filter on session variables since those values are never persisted.
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 (2-letter language code ”es”), every worksheet
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 231
Chapter 4. Trying It Out
The labels used in the buttons and prompts supplied by ODK Survey are defined in
the framework_translations sheet of the framework.xlsx file under config/assets/
framework/forms/framework.xlsx Simply add your language code and translations to this
sheet of this XLSX file and run XLSXConverter on it to enable support of your language
across all of the built-in buttons and prompts within ODK Survey.
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:
232 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
The XLSX file would then have corresponding section worksheets called pizza and birthday
that contain the survey examples documented earlier.
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:
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
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 233
Chapter 4. Trying It Out
• instances
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:
234 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 235
Chapter 4. Trying It Out
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.
Warning: 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
236 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
• If that’s too limiting, you can make a custom HTML template by setting the tem-
platePath column. Templates can include <script> and:code:<style> tags. ODK
Survey uses handlebars templates. Handlebars has a few built-in helpers for creating
conditional templates and templates with repeated components: see their documenta-
tion.
• 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
JavaScript. By providing a customPromptTypes.js file in your form directory, you
can define Backbone views that extend the base prompts.
Our HTML page rendering uses a custom database object coupled with Backbone views
to define the event handling, validation, data model interactions, and construction of the
rendering context object that is passed to Handlebars. The Handlebars templates make
use of Bootstrap framework for UI components.
Other Features
Different surveys and forms can also be entered using the external_link type, the url column,
and the url.cell_type column. 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:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 237
Chapter 4. Trying It Out
• Excel Worksheets
– Survey
* Required Columns
* Optional Columns
* Prompt Types
– Settings
– Properties
– Calculates
– Choices
– Model
238 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
– Queries
– User Defined Section
– Custom prompt_types
– column_types
– framework_translations
– common_translations
– table_specific_translations
• Built-in Functionality
– Formula Functions
Excel Worksheets
A workbook is composed of one or more worksheets. XLSX Converter expects the worksheets
within a workbook to use the following nomenclature.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 239
Chapter 4. Trying It Out
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.
properties Optional
Defines the key-value
properties that can
specify the detail, list view,
and other
properties to use with this
table. This sheet
should only be specified in
forms whose
form_id matches their
table_id.
calculates Optional
Contains the JavaScript
formulas that can be
used in other worksheets
choices Optional
Note: 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 XLSX Converter 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.
Note: 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
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 241
Chapter 4. Trying It Out
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.prompt
A string token identifying the translation
entry that can define the text,
audio, image and video to display for this
prompt.
Optional Columns
A list of the optional columns that can be incorporated into a survey worksheet is below.
242 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
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
Our documentation is updated frequently. Get the latest displayed
version 243
to the user. Used for
at https://docs.opendatakit.org/odk2.
development purposes to
leave comments about the form for future
Chapter 4. Trying It Out
Prompt Types
244 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
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
245
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
have them enter an integer
linked_table
Chapter 4. Trying It Out
Settings
setting_name
The name of the setting within the form
value
The value for the setting
display.title
A string token identifying the translation
entry with the text shown to the user
when the (survey) title is displayed.
display.locale
A string token identifying the translation
entry with the text shown to the user
when the translation locale is displayed.
246 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
table_id
Required The unique id of the table
that the form data gets
stored in.
survey
Required Specify the title of the form
via content of the
display.title.text column.
That value will
appear as the title to the
user.
form_id
Optional A unique identifier for the
form. Default value is
the unique id that ODK
Survey uses to identify the
form.
form_version
Optional A value used for version
control of the form. The
recommended format is
yearmonthday (for example:
20131212 to say the 12th of
December 2013).
<section_name>
Optional Used with display.title.text
to set how the
section name will appear to
the user on the contents
screen.
instance_name
Optional Used to display the name247
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
of
saved instances of the form.
This must be the name of a
Chapter 4. Trying It Out
Tip: 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.text column.
Tip: In the case of multiple languages, the display.locale.text column determines how the
different language options are presented to the user.
Properties
This holds the key-value settings for specifying detail and list views, and other parameters.
The columns in this sheet are:
248 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
partition
The class of property to set
aspect
key
The name of the property to set
type
Valid options: object, array, rowpath,
configpath, string, integer, number,
boolean
value
The value of the property to set
For example, the following configuration specifies that the default view for the table is the
list view (HTML). It also defines the detail view, list view, and map view HTML files. And,
for the map view, it defines the color rule to apply to the pins in the map view and the
latitude and longitude columns to use in displaying those pins.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 249
Chapter 4. Trying It Out
Calculates
calculation_name
The name used to reference the calculation
in other worksheets.
calculation
The JavaScriptf forumla to be evaluated.
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. In general,
250 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Tip: There are built in functions for ODK Survey that can be used anywhere in the
workbook. See the Forumla Functions section for more details.
If a complex calculation is required, you can access the full power of Javascript and the
jquery.js (that is: $.some_func(...) ) and underscore.js (that is: _.some_func(..
.) ) libraries. Internally, the calculate column is wrapped and evaluated as a Javascript
function:
function() {
return (YOUR_CALCULATE_COLUMN_CONTENT_HERE);
}
You can write your own code to perform a join via defining and invoking an anonymous
function in your calculate. Here is an example:
(function() {
var result = "";
_.each(data('valueListField'), function(element) {
result = result + ", " + element;
});
return result.substring(2);
}) ()
This defines a function and then invokes it. The available functions within a calculates
expression are the following:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 251
Chapter 4. Trying It Out
data(fieldName) data('myField')
Retrieve the value stored
under this fieldName
metadata(instanceMetadataFieldName) metadata('_group_modify')
Retrieve value stored under
this name
selected(promptValue, selected(data('mySelectMultipleField'
qValue) 'myChoiceDataValue')
Test whether qValue occurs
within a select-multiple
countSelected(promptValue) countSelected(data('mySelectMultipleF
Count the number of
selections in a
select-multiple
equivalent(promptValue1, equivalent(data('promptA'),
promptValue2, ...) data('promptB'))
Test if values are equivalent
now()
Return the current time
isFinalized()
Return whether or not the
current row is finalized
assign(fieldName, (8 + assign('myField',
value) 5))*10
Store value in fieldName
and return value.
252 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Additionally, the following functions are also available, but are generally not useful
in calculates. They are used within template helper functions (…/system/survey/js/
handlebarsHelpers.js).
getCurrentLocale()
Return the currently-active
locale
localize(locale, localize(getCurrentLocale(),
displayProperty) display.hint)
Localize the given
display.xxx text
width(string)
Determine the rendered
width of a string
expandFormDirRelativeUrlPath(content)
Return url for a file within
the form directory.
And, finally, you can also reference the opendatakit object (that is: opendatakit.
some_func(...) ) within these functions (system/survey/js/opendatakit.js).
Choices
The choices sheet allows you to specify the set of choices for multiple choice prompts.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 253
Chapter 4. Trying It Out
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.title
A string token identifying the translation
entry with the text shown to
the user for this choice value.
display.title.text
The text that the user sees for this choice.
display.title.image
An image that the user will see associated
with a particular choice.
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.
254 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
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.
isSessionVariable
Whether or not this field is a session
variable
(not persisted – defaults to false).
Many more columns can be specified, including a default column or, as shown in the example-
Form, a default[0] column to initialize the first element (index zero) of a select multiple field.
Default values cannot be calculates and must be simple literal values (integers, numbers and
strings).
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.
• Pass key-value maps to linked_table forms when creating or opening that form.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 255
Chapter 4. Trying It Out
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
256 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
the form
that will be used to get the results for the
4.8. ODK Application Designer
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
• properties
• choices
• queries
• calculates
• column_types
• prompt_types
• model
• framework_translations
• common_translations
• table_specific_translations
Custom 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.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 257
Chapter 4. Trying It Out
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_type_name
The name that will be used to reference
the column.
type
The type of information that will be stored
in the column (for instance, function,
formula, app_path_localized).
258 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
framework_translations
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 259
Chapter 4. Trying It Out
string_token
The name that will be used string to be
translated.
text.<locale>
The value of the translated text string.
There can be as many of these
columns as you want translated languages
(such as text.default, text.gr,
text.es).
image.<locale>
The value of the image url fragment
relative to the appName directory
for this locale. There can be as many of
these columns as you want
translated languages (such as
image.default, image.gr, image.es).
audio.<locale>
The value of the audio url fragment
relative to the appName directory
for this locale. There can be as many of
these columns as you want
translated languages (such as
audio.default, audio.gr, audio.es).
video.<locale>
The value of the videourl fragment relative
to the appName directory
for this locale. There can be as many of
these columns as you want
translated languages (such as
video.default, video.gr, video.es).
260 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
The locale code should generally be the 2-letter language code, or, if necessary, the lan-
guage_COUNTRY naming used by Android can be used to identify a specific language
variant. For example: en_US, en_UK for US English and UK English, respectively.
common_translations
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 261
Chapter 4. Trying It Out
string_token
The name that will be used string to be
translated.
text.<locale>
The value of the translated text string.
There can be as many of these
columns as you want translated languages
(such as text.default, text.gr,
text.es).
image.<locale>
The value of the image url fragment
relative to the appName directory
for this locale. There can be as many of
these columns as you want
translated languages (such as
image.default, image.gr, image.es).
audio.<locale>
The value of the audio url fragment
relative to the appName directory
for this locale. There can be as many of
these columns as you want
translated languages (such as
audio.default, audio.gr, audio.es).
video.<locale>
The value of the videourl fragment relative
to the appName directory
for this locale. There can be as many of
these columns as you want
translated languages (such as
video.default, video.gr, video.es).
262 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
The locale code should generally be the 2-letter language code, or, if necessary, the lan-
guage_COUNTRY naming used by Android can be used to identify a specific language
variant. For example: en_US, en_UK for US English and UK English, respectively.
table_specific_translations
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 263
Chapter 4. Trying It Out
string_token
The name that will be used string to be
translated.
text.<locale>
The value of the translated text string.
There can be as many of these
columns as you want translated languages
(such as text.default, text.gr,
text.es).
image.<locale>
The value of the image url fragment
relative to the appName directory
for this locale. There can be as many of
these columns as you want
translated languages (such as
image.default, image.gr, image.es).
audio.<locale>
The value of the audio url fragment
relative to the appName directory
for this locale. There can be as many of
these columns as you want
translated languages (such as
audio.default, audio.gr, audio.es).
video.<locale>
The value of the videourl fragment relative
to the appName directory
for this locale. There can be as many of
these columns as you want
translated languages (such as
video.default, video.gr, video.es).
264 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
The locale code should generally be the 2-letter language code, or, if necessary, the lan-
guage_COUNTRY naming used by Android can be used to identify a specific language
variant. For example: en_US, en_UK for US English and UK English, respectively.
Built-in Functionality
The jquery and underscore libraries are available when defining calculates expressions.
ODK Survey exposes built-in functionality through formula functions to decrease form de-
velopment time.
Formula Functions
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 265
Chapter 4. Trying It Out
assign assign('fieldname',
value)
Assignment operator that
will assign the value
to the field and return the
value
countSelected countSelected(data(‘options’))
Returns the number of
items selected from a
select_multiple prompt
data data(‘options’)
Returns the value of a field
or session variable.
equivalent equivalent(data(‘option1’),
data(‘option2’))
Check to see if two values
are equivalent
isFinalized isFinalized()
Returns true if this
submission is finalized
localize localize(data('options'))
Localizes the text passed in.
metadata metadata(‘_group_read_only’)
Returns a metadata field of
this row
not not(selected(data('examples'),
'label_features'))
Negates the argument
passed in.
now now().getDay()
266 ReturnsGet
Our documentation is updated frequently. thethecurrent dateat https://docs.opendatakit.org/odk2.
latest version
selected selected(data('visited_continents'),
4.8. ODK Application Designer
And, additionally, the opendatakit object is also available for use in calculates expressions.
Warning: The opendatakit object contains many useful functions but these should be
considered internal methods subject to change. When upgrading, be sure to confirm that
the methods you use have not disappeared!
ODK Scan uses the ODK Scan Form Designer to create machine-readable forms. Scan is
only compatible with forms created in the Scan Form Designer and loaded onto the phone.
They can then be chosen among the templates within ODK Scan and successfully processed
on the device.
Find the Scan Form Designer inside a tab in the ODK Application Designer using Google
Chrome.
Warning: You muse use Google Chrome; other web browsers are not compatible at
this time.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 267
Chapter 4. Trying It Out
Getting Started
After Launching the Application Designer, find the Scan Form Designer inside a tab (see the
ODK Application Designer Overview for a tour of all the tabs).
Warning: You must use Google Chrome; other web browsers are not compatible at
this time.
The Scan Form designer presents a default page, the toolbar across the top of the screen,
and Form Properties in the gray editing area surrounding the the page.
• Adding images, especially high resolution images, to your form will provide increased
reference points for Scan to help with aligning the form. Adding labels as images, as
opposed to text fields, can help improved the accuracy of your scans.
268 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
• Fields stretched across the page are more likely to appear curved or warped in the
photo taken by Scan, and the misalignment can lead to recognition errors. Ideally,
each field should only be a few inches wide.
• Similarly, large sized numbers can also appear stretched or misaligned; small to medium
sized numbers are recommended with 2pt spacing between each digit is recommended.
• Fill-in Bubbles can be slightly more accurate than Check Boxes.
• Ink pens are recommended over pencil when users are completing your printed form.
• You don’t need to worry about leaving space for a printable border, Scan will auto-
matically create a border around your form template.
• Currently Scan is capable of reading one-page, one-sided forms, so the Form Designer
will only allow you to create one-page, one-sided forms.
You must select the page style you want before you add any images or field boxes. You
cannot change the page style later.
Warning: If you switch the page style later everything will be cleared to the default
(blank!).
Choose your page format from the toolbar by selecting File → Set page style. The options
for page style are:
• Letter portrait
• Letter landscape
• A4 portrait
• A4 landscape
• Legal portrait
• 3x5 index card
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 269
Chapter 4. Trying It Out
Form Properties
In the workspace to the left of the form you are creating is a box titled Form Properties. This
is were you can tailor each field for style and for establishing how the data will be organized
and presented after it is scanned and digitized. The key properties to note at this point are:
• Name: An identifier for the ODK tools back end. A name is generated automatically
but can be customized if desired. No spaces allowed; if blanks are entered (for example:
”Date mo 1” it will be saved with underscores (for example, ”Date_mo1”). If desired,
the name can be the same as the display text.
• Display Text: A label for the field that relates the nature of the data input and will
be a reference point in Survey when looking at the data answers after collection (for
example: ”PolioVaccDate”). If desired, this can be the same as the name. The display
text can include spaces if desired.
• Verify field: Choose whether the field requires validation by the user reviewing the
scan when transcribing in Survey.
• Order of fields: Enter the order that the fields will be presented to the person verifying
each field of data in Survey. Provide order by listing number, for example: 1, 2, 3.
• Select Update Field to apply any changes.
Adding Images
Anchor Images
You’ll find that the default starting page of the Form Designer has images in each corner.
These anchor images act as fiducial markers, or points of reference for the ODK Scan app
when the form is eventually photographed with ODK Scan. Points of reference help the
app orient the form so it knows which fields on the paper form correspond to the fields in
the digital template. Additionally, any typed text fields that you added to the form will be
270 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
viewed as images by the app and give the app additional points of reference to orient the
form for processing.
You can customize the anchor images with your own images:
• Delete the preloaded anchor images by Deleting Field when the image is selected, and
follow the instructions below on how to add new images.
• Each corner’s anchor image must be unique, and the higher the resolution the better.
Add Images
1. To begin adding images, you must first be working on the image layer. From
the toolbar, select Edit → Images.
2. Choose the image from your computer by clicking New Image. The image
will appear in the image workspace area to the right of the form you are
editing.
3. Use cursor to select the area of the image you want to use; this can be
resized later.
4. Add Selection
5. Selected image will be placed in the upper left-hand corner of the editing
layer workspace. Drag the center of the image to place it where you want
on the form, and the corners of the image to resize it.
6. You can keep adding selections from the same image while in Image Layer
mode.
7. Return to Edit → Field to add more fields.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 271
Chapter 4. Trying It Out
8. If you return to Edit → Image to add more images, you will see the previ-
ously uploaded files in the righthand corner of the workspace. Click on a
file to quickly load the image for selection.
In addition to customizing the anchor images on your form and adding additional points of
reference to guide the ODK Scan app, you may also want to use images to:
• Add a logo or picture
• Add tables or charts to the form
• You want to add text without typing it out in the Text field of the form designer. This
is helpful if you are working off an existing form and do not want to retype all of the
text from the form. You can grab images of the text instead and upload it to use in
the form designer.
To begin adding data fields, you must first be working on the Fields layer by selecting from
the toolbar Edit → Fields.
There are seven different field inputs that are supported by the ODK Scan Form Designer.
Two of these field do NOT support digitization:
272 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
• Text Box
• Text
And five allow for automatic digitization
• QR Code
• Checkboxes
• Fill-in Bubbles
• Number
• Formatted Number
To add a field, select Add → (desired field). Once you’ve added a field, the field will appear
in the top left section of the form. You can then drag and drop the field to the placement
you want on the form, as well as shrink or expand the field by pulling the corner.
Text Box
This will be a blank field where users will write in information. In the scanning process, text
boxes capture an image of what has been written in the box, but they do not automatically
digitize the letters.
Note: To digitize a text box, a user will manually transcribe the image of the text box
into a text prompt in ODK Survey.
Text
This is one way you add typed text to a form. Text fields are not an input field for users
and will not be digitized by scan, but act more as labels for fields that will be automatically
digitized. Text fields also help ODK Scan orient the photo of the scanned form to the
template file by providing additional points of reference.
QR Code
A matrix barcode that can contained encoded numbers, words, or other data.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 273
Chapter 4. Trying It Out
When a form with a QR code box is scanned, the ODK Scan App will process any QR code
data inside that area. This is designed for a process such as placing a unique patient ID
code sticker on a printed form and then using the ODK Scan app to automatically link the
encoded data with the other data elements on the form. The only stipulation is that the QR
code must fit inside the box whose size you specify in the form designer.
To create a custom QR code, you can use an online QR code generator, such as these
example: QR Code Generator or QR Stuff.
Once you have a QR code saved as an image, you can add it to your form like any other
image file. See Adding Images for more information.
For ODK Scan, Fill-In Bubbles and Checkboxes have the same functionalities and options;
they only vary in how they look.
Note: Fill-in bubble option results in slightly more accurate scan results than similar
checkboxes.
With checkboxes or fill-in bubbles there are a few additional elements to consider in Form
Properties.
Bubble Type
The Bubble type field allows you to select how to categorize and count user entries.
• Tally: Filled bubbles will be read by ODK Scan as one unit each and will be
added up to result in a number value. Each filled bubble/checkbox is one tally
mark. (for example, one filled bubble for each child vaccinated).
• Select one: User chooses only one answer to the prompt. (for example, Male or
Female).
• Select many: User chooses all applicable answers. (for example, Reasons for extra
care: Low birth weight, family history of infant death, twins…).
274 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Grid Values
Grid Values are the values designated to each bubble or box. The default value for each
bubble or box filled in by the user is 1, and you can customize the answers ODK Scan
attributes to each box or bubble. For example, if in a grid of one row and two columns, row
1, col 1 is given the value of ”yes,” when that box is marked by a user in Survey and Tables
the digitized answer will be ”yes.”
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 275
Chapter 4. Trying It Out
The Number field is to add a number input that does not need any special formatting (for
example, it’s not a date, decimal, or a number split up by a dash). It is what you should
use for things like number of polio vials in stock, age of child, and patient ID number.
The Formatted Number field has an option for digits to be split up by delimiters, allowing
you to create a date, decimal, and dashed-number input. This is what you should use for
things like date of registration and infant weight, and for anything like a serial number or
refrigerator product code where the number is broken up by a dash.
276 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Warning: Scan’s accuracy for number digitization is not as high as it is for the other
fields. Bubbles and checkboxes have been tested at 99% accuracy in the field, but number
accuracy can dip into the 80s or worse depending on form design and field conditions.
If you plan to use numbers in your form, be sure to review the Tips & Recommendations
section and test your form in field conditions.
Group Options
At the far right of the toolbar is Group Options, which allows you to create subforms. With
subforms you can link several fields together, useful when wanting to move multiples fields
around your form at once and keep them together
1. While holding the Shift key, select all the fields you want to group together.
2. From the toolbar, select Group Options → Group Fields.
3. A dialog box will appear asking to confirm that you want to make a subform. After
selecting Yes, you will need to name this subform.
If you need to ungroup fields, with the subgroup selected, from the toolbar select Group
Options → Ungroup Fields.
Save Incomplete
If you are working on a form and wish to save it for future editing, go to File → Save
Incomplete to save the .zip file to your computer.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 277
Chapter 4. Trying It Out
Load Incomplete
When you return to continue working on a saved form, go to File > Load Incomplete and
select the .zip from your computer. Make sure it is still in the .zip format and is not an
unzipped folder.
278 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
Warning: Always make sure to SAVE your form this way, even if you are also exporting
or saving to file system. This is the ONLY way to reload a form if you want to make
changes. The exported file will NOT work if you try to load it back into the form designer.
Once your form is complete, you are ready to generate the machine readable files. Go to
File → Save to File System. Give the file the name you will want to see it called in the app
and in Survey and Tables, as you will not be able to change this name later.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 279
Chapter 4. Trying It Out
This will generate the JSON template file, JPG form photo, and all other files necessary for
the Scan app to read and process your forms. It will save them to the application file system,
which can be pushed to the device using Grunt with the typical command for pushing your
app to your device (performed inside the Application Designer directory:
$ grunt adbpush
Warning: Saving to the file system does NOT save a version that can be edited later.
Please use the Save Incomplete function to get an editable file.
If you would prefer to export your Scan machine readable files externally from the file system,
you can use this option. Go to File → Export Completed Form. Give the export file the
name you will want to see it called in the app and in Survey and Tables, as you will not be
able to change this name later.
280 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.8. ODK Application Designer
This will give you a .zip file that you can unzip and use to print hard copies of your form
and transfer your form .json template to the ODK Scan App.
Note: This step is NOT necessary. Most people will use the ”Save to File System” option.
After you have saved and exported your form, print hard copies for your user to complete.
1. From the location you saved it on your computer, unzip the exported file.
2. Within the folder, find and open the file called form .jpg. This is the image
of the form that you created in the Form Designer is the form you will print
to hard copy.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 281
Chapter 4. Trying It Out
3. Print the entire image on one page. Black and white is fine even for forms
that were created with colored elements.
General
• Use only Google Chrome to access the form designer! Other browsers are not compat-
ible and may cause you to lose the form you’re working on.
• Make sure your browser zoom is set to 100%. Zooming out can cause the data fields
to appear weird on the form.
• Do not refresh your browser without first saving your form – the form will be
reset to the default blank form.
• The Copy function, can be an easy shortcut if you need to create multiples of the same
field. This could be useful, for example, if on your form you want to collect the date
of birth for each child in the family, or need to create multiple entries for dates of
treatment.
• With the field you want to copy selected, go to Copy on the toolbar, and the new field
will appear in the top left of the form. Edit any of the Form Properties as needed.
• Grouping fields together can be a shortcut when needing to move multiple fields around
as you’re working on your form; instead of moving them one at a time.
• You can both Delete and Undo Delete for fields and images from the toolbar.
Design Considerations
• Currently Scan is capable of reading one-page, one-sided forms, so the Form Designer
will only allow you to create one-page, one-sided forms.
• Numbers left blank will be recognized by Scan as ”” (the empty string).
• Therefore, if for instance you have a field that can have a range in the number of digits
(for example, like Patient ID Numbers where one patient’s ID could be 5 digits long,
and another’s 7 digits) create a text field to give your user instructions to leave any
blank digits at the front of the field, so that those blanks will not not alter the final
value interpreted by Scan.
• Since Scan cannot digitize handwriting, and text will have to be manually typed in
when verifying the data set, if the form you are basing your template on is text heavy
think creatively and strategically about the ways you can use bubbles or checkboxes
instead.
282 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.9. ODK Cloud Endpoints
• For example, instead of asking users to write in their symptoms, you can provide
bubbles for the most common symptoms, and leave a Text Box for anything not listed.
• Repeat formatting for forms with multiple sections to make it as easy as possible for
those writing in information to navigate the fields and the form. For example, place
labels in the same position for each field, group subsections close together and create
borders around them, and so on.
• Think through the order that users will be collecting information and try to best
replicate that in the order that fields are presented on the form.
• For example, if the person completing the form will ask about the child’s age before
asking about the vaccines they have had (or if you want them to ask about age first),
place the number field for age earlier in the form’s progression than fields for the
vaccines.
• Be strategic about when using fill-in bubbles or checkboxes. To not confuse your user,
it is best to use just one type on the form. Alternatively, you can use both to signal
the different types of responses that can be given; for example, use fill-in bubbles for
all of your select one questions, and checkboxes for select many, to signify to your user
that they are being asked a different type of question.
• Fields by default are created with borders. In the Form Properties box you can change
the thickness of borders, number of borders, as well as the margins surrounding the
fields.
• Use the arrow keys on your keyboard to move selected fields more exactly.
• You can align fields relative to each other by holding down Shift to select multiple
fields at once, and then go to Align Field to select the alignment you want for the
selected fields.
• Using the Change Position function, located on the toolbar, if fields are placed close
enough that they overlap, by sending one field forward or backward, you can overlay
them to best fit your form.
ODK Cloud Endpoints are servers that communicate with the ODK-X Android applications.
They implement the ODK-X REST Protocol.
There are currently two options for Cloud Endpoints to communicate with ODK-X tools.
• ODK Sync Endpoint - Supports the full ODK-X REST Protocol
• ODK Aggregate Tables Extension - Supports the majority of the ODK-X REST Pro-
tocol; however, is missing group permission filtering support.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 283
Chapter 4. Trying It Out
ODK Sync Endpoint is an implementation of ODK Cloud Endpoints. It runs a server inside
a Docker container that implements the ODK-X REST Protocol.
It communicates with your ODK-X Android applications to synchronize your data and ap-
plication files.
Authentication
ODK Sync Endpoint does not store user information in its own database, instead it integrates
with an LDAP directory or an Active Directory. That directory is then used to authenticate
users and obtain user roles.
You must have Docker 17.06.1 or newer, and be running in Swarm Mode. Follow these
links for detailed instructions on installing Docker and enabling Swarm Mode.
• Docker
• Swarm Mode
ODK Sync Endpoint requires a database and a LDAP directory, you could follow the in-
structions and deploy all three components together or supply your own database and/or
LDAP directory.
284 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.9. ODK Cloud Endpoints
Setup instructions:
1. Choose a directory to store you endpoint in. In that directory, run:
$ cd sync-endpoint
4. Build sync endpoint by running the following: (NOTE: you will need Apache
Maven installed >= 3.3.3)
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 285
Chapter 4. Trying It Out
Note: It is important that the right side of the colon stays as 8080.
This is the internal port that the web server is looking for.
12. If you’re using your own LDAP directory or database, continue with the
instructions:
• Custom database instructions
• Custom LDAP instructions
13. In the cloned repository:
14. The server takes about 30s to start, then it will be running at http://127.
0.0.1.
15. See the LDAP section for instructions on configuring users and groups.
Custom database
6. The server takes about 30s to start, then it will be running at http://127.
0.0.1.
286 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.9. ODK Cloud Endpoints
Note: The default configuration does not use ldaps or StartTLS because the
LDAP directory communicates with the ODK Sync Endpoint over a secure over-
lay network. You should use ldaps or StartTLS to communicate with your LDAP
directory.
6. The server takes about 30s to start, then it will be running at http://127.
0.0.1.
1. Run:
• Windows:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 287
Chapter 4. Trying It Out
LDAP
• Windows:
Note: The phpLDAPadmin server listens on port 40000, it is important that you do not
expose this port to the internet.
The following guides assume that you’re using phpLDAPadmin. In order to perform the
following operation, please go to https://127.0.0.1:40000 in your browser.
Creating users
288 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.9. ODK Cloud Endpoints
Creating groups
Note: The group name must start with the group prefix, in this case the group
prefix is default_prefix so for example: default_prefix my-new-group
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 289
Chapter 4. Trying It Out
HTTPS
1. Store your certificate public key in a Docker config with this command:
2. Store your certificate private key in a Docker secret with this command:
ODK Aggregate Tables Extensions enable the ODK-X tools to share data via bi-directional
synchronization with a central ODK Aggregate server.
The ODK REST Protocol is compatible with ODK Aggregate v1.4.15. The sync protocol
has been augmented to cache the user’s permissions on the device and, for super-users or
administrators, to cache the full set of users and all of their permissions (so that the super-
user and/or administrator can assign rows to particular individuals).
Server Setup
First you’ll have to install ODK Aggregate v1.4.15 to a server (see Installing Aggregate).
1. Install ODK Aggregate v1.4.15 to a server.
2. Log onto your ODK Aggregate v1.4.15 instance.
3. Go to the Site Admin → Preferences page.
4. Check the checkbox for ODK Tables Synchronization Functionality.
5. Go to the Site Admin → Permissions page.
6. Add ODK Aggregate usernames by typing one or more users’ e-mail addresses into the
text area and clicking Add User.
7. If you have created an ODK Aggregate username, be sure to Change Password on that
account to set the initial password for the account.
8. Grant these users the Synchronize Tables permissions.
9. Select at least one user to be the administrator and grant them Administer Tables
permissions. This user will have the ability to Reset App Server from the Android
290 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.10. ODK Suitcase
device and add or remove tables and configuration files on the server. This is the
equivalent of the Form Manager permissions in ODK deployments.
10. Click Save Changes. These changes will not take effect until you do!
Note: The ODK-X tools are designed to support multiple, independent, ODK-X applica-
tions running on the Android device. Each of the tools has the ability to run in the context
of either a default application name, or a specified application name.
By default, all the ODK-X tools run under the default application name. Application names
correspond to the name of the directory under /sdcard/opendatakit where the data files
for that application are stored.
When you run ODK Services from within ODK Survey, the ODK Survey tool informs ODK
Services to run in the context of the application name under which the ODK Survey tool is
running. When ODK Services then interacts with ODK Aggregate, it reports that applica-
tion name to the server. The server must be configured with exactly the same application
name or it will reject the requests from ODK Services. This also applies when launching
ODK Services from within ODK Tables.
ODK Suitcase is a cross-platform tool that provides access to data on an ODK Cloud End-
point from a personal computer.
Data downloaded from an ODK Cloud Endpoints is stored as spreadsheets in CSV format.
This format is compatible with most spreadsheet software, for example Excel or Numbers.
Once downloaded, the spreadsheets will be available for offline viewing. Similarly, data to
be uploaded to an ODK Cloud Endpoint must be stored in a properly formatted csv file.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 291
Chapter 4. Trying It Out
Prerequisites
Note: Ensure you are using a compatible Cloud Endpoint from the
same revision.
2. Make sure Java 7 or higher is installed on the computer you plan to use. If
it is not, download and install it.
3. Alternatively you can use command line operation. For help on the com-
mand line interface type:
Graphical Interface
If your ODK Cloud Endpoint allows for anonymous access then you can leave the username
and password fields blank. Otherwise, please specify an ODK Cloud Endpoint username and
password with sufficient permissions.
By default ODK Suitcase creates a Download directory where the ODK Suitcase jar file is
located and saves data in that directory. To specify a different directory for ODK Suitcase
to store downloaded data in, click on the … button.
ODK Suitcase provides three options to customize the CSV file.
• Download attachments:
292 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.10. ODK Suitcase
– If this option is selected, ODK Suitcase will download all attachments from the
given table and the CSV generated will contain hyperlinks to the local files.
– If this option is not selected, the CSV generated will contain hyperlink to the
given ODK Cloud Endpoint.
• Apply Scan formatting:
– When this option is selected, ODK Suitcase will optimize the CSV by replacing
certain columns added by ODK Scan.
• Extra metadata columns
– When this option is selected, two more columns will be included in the CSV,
create_user and last_update_user.
ODK Suitcase also provides a command line interface that can be easily called by scripts
and other programs. The CLI has the same features as the graphical user interface. CSV
files produced by the two interfaces should also be identical.
For a list of all available options, open command prompt/power shell or terminal. Type:
Combine the individual commands described in the help to perform the actions needed.
Examples are as follows.
• To download CSV of table table_id from app default with attachments as an anony-
mous user to the default directory.
• To download CSV of table table_id from app default with attachments with username
user and password pass to:file:‘ ~/Desktop‘:
To script the CLI, write the commands you would like to execute in a scripting language
(for example, Bash, Batch, Python, Ruby) and use a scheduler (such as Cron or Windows
Task Scheduler) to schedule the tasks. To skip over ODK Suitcase’s prompts to overwrite,
pass -f as an argument to ODK Suitcase.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 293
Chapter 4. Trying It Out
This will walk you through the steps of building a Data Management Application from
scratch. The goal is to start with an empty folder and show you the necessary steps to
create a working application that runs on your Android device.
Note: This section covers topics useful to Deployment Architects. A Deployment Architect
is an author of a data management application or a consumer of collected data. This person
might create forms and edit Javascript on their computer to deploy to the Android device.
Or they might download data from the server and use Excel to perform analysis. Examples
include technical staff and data analytics staff.
Other perspective definitions can be found here.
4.11.1 Prerequisites
Your freshly installed copy of Application Designer comes with lots of example forms, tables,
and configuration. This is useful for learning the tools and as references when building our
application, but the files should be cleaned before building your own application.
Enter your Application Designer directory, navigate to app/config/ and delete everything
inside the directory.
294 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.11. Building an Application
When creating a new form, the appropriate directory structure must be created. Once this
directory structure is in place, an .xlsx form can be created. From this .xlsx form, a
formDef.json file will be generated using the XLSX Converter. This formDef.json, in the
appropriate directory, is what the system will use to create the Survey form.
New forms must be placed under the app/config/tables/ directory as described in the
The app/config/tables/ Folder section. Given a form with the name formId, it will have a
tableId of the same name unless you explicitly specify otherwise. The directory structure
that should be created is app/config/tables/tableId/forms/formId (where, under many
circumstances, the value for tableId will be the same as the value for formId). To get
started, for Windows open a cmd window within your Application Designer folder (click
the cmd shortcut you created earlier), and for Mac/Unix open a terminal window within
your Application Designer folder. Type:
$ grunt addtable:tableId
Where tableId is the name of your new form and table. For example, to create a census
form, type:
$ grunt addtable:census
This will create the required directory structure for an individual table, including the forms
directory. It also created basic HTML and JavaScript files, which will be covered later.
Navigate into the forms directory (app/config/tables/census/forms/ in our example),
and create a directory with the form ID as its name. For our example, create a app/config/
tables/census/forms/census directory. Within that directory, ODK Survey expects to
find the formDef.json that defines the form.
Tip: We recommend placing the .xlsx file used to generate that formDef.json in this
folder as well. Survey will not use this file, but it is a useful reference and provides an easy
to remember storage location in case the form needs to be updated in the future.
Any custom screen, prompt templates, or other media related to the form should be also
placed in this directory (or in a sub-directory).
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 295
Chapter 4. Trying It Out
With the proper directory structure in place, you can now create your form. The ODK
XLSX Converter documentation extensively details the full range of options, settings, and
features available when creating a form. For this basic example, follow these instructions:
1. Create a new file census.xlsx inside the app/config/tables/census/
forms/census folder created in the previous section.
2. Create a settings worksheet. This sheet holds general settings for the form.
Create the following headers:
• setting_name: has defined options, such as form_id.
• value: the value of the named setting.
• display.title.text: the text shown to the user inside Survey.
Reminder: the settings worksheet, and any other worksheets to be
defined later, are to be created within the .xlsx file you created above.
DO NOT create separate .xlsx files for each worksheet.
3. Create the following rows:
4. Create a survey worksheet. This sheet defines the questions and flow of your
form. Create the following headers:
• type: the prompt type.
• values_list: the name of the list of choices for a multiple choice question.
• name: the variable name.
• display.promp.text: the question the user will see in Survey
5. Create the following rows:
296 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.11. Building an Application
6. Create a choices worksheet. This sheet contains the lists of responses you
define for your multiple choice questions. Add the following headers:
• choice_list_name: the group name for all the responses in a choice set
• data_value: the data value to be selected
• display.title.text: the text the user will see to select this value
7. Create the following rows:
With this .xlsx file you’ve created a simple Survey form that will ask the user to type in
their name and respond whether they are 18 years old or not. This form will be titled Census
and it will write to a table in the database with table ID census.
Creating framework.xlsx
The framework.xlsx file is central to the structure of the Application Designer. It defines
which forms exist. It has no persisted data. In this case, it only presents a list of forms and
allows you to open them.
1. Create the following directories: config/assets/framework/forms/.
2. Inside that folder, create framework.xlsx
3. Create an initial worksheet. Add header: clause and value do section survey.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 297
Chapter 4. Trying It Out
9. Create a survey sheet. Add the headers: branch_label, url, clause, condi-
tion, type, values_list, display.prompt.text.
10. Add the following rows. They tell the software what to do if you’re pre-
viewing in Chrome.
Note: This is only tested and expected to work in Chrome and not other
browsers like Firefox, Safari, or Edge.
298 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.11. Building an Application
opendatakit.getPlatformInfo().container
==
”Chrome”
user_branch
test_forms Choose a
test form
else
note This
is the
default
form.
end if
exit sec-
tion
census
external_link Open
form
’?’ +
odkSur-
vey.getHashString(’census’)
exit sec-
tion
Updating framework.xlsx
To add another new form to an existing framework.xlsx file, take the following steps.
Note: These steps are not part of the running example. They are provided here for
reference.
Assuming you have created a testForm.xlsx, the appropriate directory structures for
testForm.xlsx, and then properly generated and saved the formDef.json, the following
lines would need to be added into the framework.xlsx survey worksheet.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 299
Chapter 4. Trying It Out
The following changes will also need to be made to the framework.xlsx choices worksheet
The changes to the choices sheet add the testForm form as one of the choices that is shown
in the user_branch prompt (a user-directed branching prompt type). The changes on the
survey sheet add a branch label, testForm, that matches the data_value from the choices
sheet (this branch label will be jumped to if the user selects the testForm selection on the
user_branch screen). The new branch label then renders an external_link prompt type that
has the necessary arguments to open the testForm.
Generating formDef.json
Once you have a saved your .xlsx file, you can use the XLSX Converter to create a formDef.
json. Make sure your Application Designer is running (see Launching the Application De-
signer) and navigate to the XLSX Converter tab. Drag the .xlsx form or select it with the
Choose File button and use the Save to File System button to save the form definition file
back to the file system.
For the ongoing example, convert the app/config/assets/framework.xlsx using the
instructions above. Then repeat this process with app/config/tables/census/forms/
census/census.xlsx
Warning: The Save to File System button uses the form_id and table_id within the
.xlsx file to identify where to write the formDef.json file. If you have copied the .xlsx
file from some other location, and forgot to edit it, it may update back to that older
300 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.11. Building an Application
location! If the form_id is equal to the table_id, two additional files are written that
define the table’s user data fields and that define the key-value properties for the table.
Once you have made these changes and used XLSX Converter on the framework.xlsx file
to update the app/config/assets/framework/forms/framework/formDef.json file, you
should see your new form show up in the Preview tab of the Application Designer. Clicking
on that should open your form.
Tip: If you don’t see your form in the Preview, try refreshing your browser.
Tip: You can also convert your forms with the Grunt command:
grunt xlsx-convert-all
The XLSX Converter should report most problems with your survey.
If the form is not being rendered correctly but your survey generates a formDef.json without
an error, first try purging the database (dropping all the existing data tables) using the Purge
Database button on the Preview tab. You will typically need to purge the database whenever
you add or remove fields from your form or change their data type.
If that does not resolve the issue, try stopping the grunt command (on Windows, Control-C
should produce a prompt asking to confirm whether to stop or not. On Mac, Control-C
kill the process with no prompt.), and re-running it. Grunt can sometimes get overwhelmed
with changes and stop working. After restarting, test your form.
If there are other problems, the contents of the JavaScript Console will be helpful to the
ODK core team for debugging. Open the JavaScript Console by clicking the icon with the
three bars in the top right, select More Tools, select Developer Tools, and then select the
Console tab. Select all of the debugging output, then copy it, save it to a file, and post it to
the ODK Forum or create a ticket on the Github Issue Tracker.
Note: You must have USB debugging enabled on your device in order to perform this step.
See these instructions for help.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 301
Chapter 4. Trying It Out
In order to see these changes on an Android device, you must first have ODK Survey installed
on your device. Then:
1. Connect the device to your computer via a USB cable
2. Open a cmd or terminal window within the Application Designer directory
(the one containing Gruntfile.js), as described in the Application Designer
Directory Structure documentation.
3. Type:
$ grunt adbpush
Note: If it gives you an error, you may need to run grunt adbpush -f to force
it.
Note: If you do not see the form, you may need to reset the configuration.
This will copy all of the files under config onto your device. You should then be able to
launch ODK Survey, and it will display your form in its list of forms. Click the form to open
it.
More grunt commands can be found in Pushing and Pulling Files.
One of the most powerful aspects of ODK Tables is its ability to run HTML and JavaScript
pages as the skin of the app. Through a JavaScript API presented to these files, you can
query the database and control the app.
Writing an app using HTML and JavaScript yields a lot of power. However, it can lead to
a complicated design cycle.
The HTML and JavaScript files you write rely on the JavaScript API implemented within
the ODK Tables APK to retrieve database values for your application. This JavaScript API,
since it is implemented in the APK, makes it difficult to debug your custom views off the
phone. At present, the only way to test your HTML pages is on the device. Fortunately, on
Android 4.4 and higher, Chrome can access the browser Console and set breakpoints on the
device, providing a clumsy but viable debug environment.
302 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.11. Building an Application
There are several pieces of boilerplate you have to include in your own code in order to debug
the files in Chrome.
In the default Application Designer, open app/config/tables/Tea_houses/html/
Tea_houses_list.html. Alternatively, if you are doing the running example, open app/
config/tables/census/html/census_list.html, which should have been automatically
created for you. Notice the following four lines in <head>:
In the first line you are making the jQuery object available to your code. jQuery is a
powerful, commonly used set of functions for accessing and performing actions within a
webpage. In the next three lines you are adding the odkCommon, odkTables, and odkData
objects if they are not already provided by the browser environment. When running on
the device, the ODK Tables APK will provide these, and the contents of these files will
be ignored. When running in Application Designer on your computer, these files provide
the approximate functionality of the APK, allowing you to create and debug your scripts.
However, at the moment, these implementations make use of RequireJS, which the ODK
Tables HTML files do not use (RequireJS is extensively used by ODK Survey). This causes
these to break in Application Designer Previews.
More detail is provided in ODK Tables Web Pages.
To write your own file, first decide on the tableId for your table and instantiate a directory
using the grunt command:
$ grunt addtable:tableId
If you completed the example in ODK Survey: Designing a Form you have already done this
for the census table.
This grunt task creates the needed directory structures and also constructs the HTML
and JavaScript files with the necessary features for working within the Chrome development
environment.
Note: These files need content from your data table to display. It is recommended that
you first design a Survey form (for example, using this guide) which you can use to populate
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 303
Chapter 4. Trying It Out
data. You can also prepopulate data into the database with a tables.init file. Further
instructions are available in the Configuring an App at Startup guide.
</head>
<body>
<script type="text/javascript" src="../js/census_list.js"></script>
<div id="wrapper">
<div id="list"></div>
</div>
<script>
$(function() { resumeFn(0); });
</script>
</body>
</html>
This HTML file should be minimal. It links all the source files and provides <div> to put
the list in. Most of the work happens in the JavaScript file. Open or create app/tables/
census/js/census_list.js. Ensure its contents look like this:
304 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.11. Building an Application
}
});
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 305
Chapter 4. Trying It Out
chevron.attr('class', 'chevron');
item.append(chevron);
The HTML and JavaScript files also depend on a few more files. For convenience, the
example reuses CSS and image files from the ODK Tables: Sample Application. Open up
a default Application Designer and copy the following files to this application’s directory
(using the same directory paths):
• config/assets/css/list.css
• config/assets/img/little_arrow.png
• config/assets/libs/jquery-3.2.1.js
A Detail View will display the details of a record. It is commonly used alongside List View
to provide options to browse through a data set and learn more about a particular record.
Open or create app/tables/census/html/census_detail.js Ensure the file looks like this:
306 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.11. Building an Application
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="../../../assets/css/detail.css" type="text/css" rel=
,→"stylesheet" />
</head>
<body>
<script type="text/javascript" src="../js/census_detail.js"></script>
<fieldset>
Is over 18: <input id="FIELD_1" type="checkbox" name="isAdult" />
</fieldset>
<script>
$(display); // calls the detail display function when ready
</script>
</body>
</html>
This HTML file should define the user interface elements that will be populated by database
calls in the JavaScript. Open or create app/tables/census/js/census_detail.js. Ensure
its contents look like this:
/* global $, odkTables, odkData */
'use strict';
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 307
Chapter 4. Trying It Out
censusResultSet = result;
// and update the document with the values for this record
updateContent();
}
function cbFailure(error) {
// a real application would perhaps clear the document fiels if there were an␣
,→ error
console.log('census_detail getViewData CB error : ' + error);
}
/**
* Assumes censusResultSet has valid content.
*
* Updates the document content with the information from the censusResultSet
*/
function updateContent() {
nullCaseHelper('name', '#TITLE');
/**
* Assumes censusResultSet has valid content
*
* Updates document field with the value for the elementKey
*/
function nullCaseHelper(elementKey, documentSelector) {
var temp = censusResultSet.get(elementKey);
if (temp !== null && temp !== undefined) {
$(documentSelector).text(temp);
}
}
308 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.11. Building an Application
As with the List View, this view requires a separate CSS file. Copy the following file from a
default Application Designer, maintaining the directory path in this application’s directory:
• config/assets/css/detail.css
The .xlsx form should be updated to indicate the default view type, and where to find
the HTML files for Detail View and List View. Open app/config/tables/census/forms/
census/census.xlsx and add a new worksheet titled properties. Add the following headers:
partition, aspect, key, type, and value.
Add the following rows to set your List View and Detail View default files:
See Properties for more details about specifying custom HTML files.
Run census.xlsx through the XLSX Converter again (Generating formDef.json) to update
the configuration.
After that, you can deploy your app to your device. Open Survey and fill in a few census
records. Then, open Tables and select the Census table. This should automatically launch
the List View defined above. Tapping an item in the List View should launch the detail
view.
You can use the Chrome browser on your computer to inspect for devices and connect to this
custom screen on your Android device, and debug from there. Some useful guides include:
• Get Started with Debugging JavaScript in Chrome DevTools
• Get Started with Remote Debugging Android Devices
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 309
Chapter 4. Trying It Out
Warning: The edit-debug cycle is awkward because you must make the HTML or
JavaScript change on your computer then push the change to your device, and reload
the page (for example, by rotating the screen). When you do rotate the screen, however,
it is rendered in a new web page, necessitating connecting to that new page to resume
debugging (the prior page sits idle and will eventually be destroyed. If you don’t see any
activity, it is likely because you are pointing at the wrong web page. Return to inspect
devices, and select the newest page).
As with ODK Survey, you can use the JavaScript Console to look for and fix errors in your
HTML/JavaScript. If you are having trouble please check on the ODK Forum. Keep in
mind that the debug objects only emit a subset of the data in your ODK Tables database.
Note: You must have USB debugging enabled on your device in order to perform this step.
See these instructions for help.
There are several times during app development where you will need to push and pull files
to and from the phone. You will have to open one of the ODK tools on the device before
these commands succeed.
• The push command is used to push the entire app directory to the mobile device.
• The pull command is used to pull the database or exported CSVs from the device to
the desktop computer.
Tip: Exported CSVs can be used to set up tables.init to load test data.
Grunt tasks have been written in Gruntfile.js that perform these operations for you.
These commands can be run anywhere within the Application Designer directory.
• grunt adbpush: Pushes everything under the app directory to the device.
• grunt adbpull-db: Pulls the database from the device to the PC.
• grunt adbpull-csv: Pull the exported CSVs from the device to the PC.
The pull commands will place the pulled content in the app/output/ directory.
The database is a SQLite database and can be viewed using SQLite Browser. This tool
can also be used to view the content of the database used by Chrome on your computer (the
location of that file is OS dependent).
310 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.12. ODK Tables Web Pages
If you pull the CSV files, they will be under the output/csv/ directory. You can then copy
them to the config/assets/csv/ directory and set up the tables.init file to read them
in order to provision test data for your development effort. If you need any of this data
in production, you will want to sync to a server then export the CSV files and copy them
to the config/assets/csv/ directory so that they have all of their metadata field values
populated.
Tip: Running grunt adbpull will perform all the pull tasks.
Tip: There are a number of additional grunt tasks available. Assuming you have installed
grunt and node, you can view the available tasks by running grunt --help anywhere in the
repo.
This step requires that you first set up a ODK Cloud Endpoints.
1. Push your application to a clean device (guide: Pushing and Pulling Files).
2. Authenticate as a user in the table administrator group (guide: Authenticating Users).
3. Reset the App Server (guide: Resetting the App Server).
The application is now deployed to your server. Other devices can synchronize with that
server to download the application and start collected data.
Updating an Application
To update any app level or table level files, or to modify the database schema (like adding a
new field to your form that adds a database column), you will need to reset the app server.
Make the changes on your PC as normal, push them to the device, and reset the app server.
Warning: Resetting the app server will start a new data set. If you want
to keep the old data, you should download it to a separate database.
Tables does not impose any structure to the HTML files a user may write. While the
odkDataIf and odkCommonIf interfaces will always be injected into the WebKit, it is up to
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 311
Chapter 4. Trying It Out
the user whether or not they make use of them (which generally means loading the odkData
and odkCommon wrapper objects). A typical HTML file might be as follows:
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="../../../assets/css/your.css" type="text/css" rel="stylesheet
,→" />
</script>
</body>
</html>
The DOCTYPE header defines the file compliance level (in this case, HTML 4.01 Transitional).
The <head> section sets the viewport and loads your CSS file. It will then typically
load the 5 standard JavaScript files needed to support translations and the injected inter-
faces (commonDefinitions.js, tableSpecificDefinitions.js, odkCommon.js, odkData.
js, and odkTables.js). This example then loads the 3rd-party JavaScript libraries that
the user needs and which the user has provided in the /config/assets/libs directory and,
finally, loads the JavaScript file they crafted that is specific to this web page (example.js).
312 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.13. Injected JavaScript Interfaces
Once all the scripts and resources on the page have loaded, the script tag at the bottom of
the <body> section will invoke the display() function which was presumably specified in the
user’s example.js file.
If the web page can launch other web pages or external applications, and if it cares about
the status of those requests or needs to process the extras in the result intents returned from
those requests (e.g., to interpret a barcode), then the user’s display() function, after it has
initialized the page, should register a listener for action outcomes and call that listener once,
directly, to process any outcome received prior to that registration (it will commonly be the
case that these will have been received prior to the registration of this listener).
See the comments at the top of the odkCommon.js file for details.
• odkCommon.js
• odkData.js
• odkTables.js
• odkSurvey.js
• Other system/survey/js files
The Java framework on the Android device injects two Java interfaces (odkCommonIf and
odkDataIf ) into both Tables and Survey WebKits. Additionally, it injects one additional
Java interface into each: odkTablesIf into Tables WebKits and odkSurveyStateManagement
into Survey WebKits.
Within the Javascript, it is expected that all interactions with these interfaces will be done
through wrapper objects. Specifically, for odkCommonIf and odkDataIf, Javascript program-
mers would invoke methods on the odkCommon and odkData objects defined in
• system/js/odkCommon.js
• system/js/odkData.js
The Tables-specific interface is interacted with via the odkTables object defined in:
• system/tables/js/odkTables.js
This wrapper object mostly invokes odkCommon to perform its actions, but does call the
odkTablesIf injected interface’s one method to load the list view portion of the split-screen
detail-with-list-view layout.
The Survey interface is invoked within the Javascript that implements the survey presenta-
tion and navigation logic and should not be directly called by form designers.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 313
Chapter 4. Trying It Out
4.13.1 odkCommon.js
This creates a window.odkCommon object that wraps calls to the injected odkCommonIf
Java interface. When loaded inside the App Designer, it also creates a mock implementation
of the injected interface.
This class provides support for:
1. obtaining information about the runtime environment (e.g., Android OS version, etc.)
2. obtaining information about the currently-selected locale.
3. obtain the active user.
4. obtain system properties (e.g., deviceId).
5. emitting log messages to an application log.
6. translations of text, media files and urls.
7. conversion functions for retrieving and storing timestamps and intervals.
8. storing and retrieving session variables (transient values that persist for the lifetime of
this WebKit).
9. converting relative paths of configuration files and of row-level attachments into URLs
suitable for use in HTML documents (e.g., image src attributes).
10. constructing form references used to launch ODK Survey.
11. invoking arbitrary intents (external programs) on Android devices.
12. obtaining the results from an intent that was previously invoked.
13. exiting the current WebKit and specifying a return intent status value and extras
bundle.
The explicit session variable interfaces (odkCommon.getSessionVariable(elementPath)
and odkCommon.setSessionVariable(elementPath, value)) provide a mechanism to pre-
serve the state of a webpage within the Java Activity stack so that no matter how nested the
call stack to external applications becomes, it can be unwound and the state of the webpage
recovered. Similarly, the invoking of arbitrary intents and the retrieving of their result intent
status and extras bundle (excluding byte arrays) provides direct access to Android’s native
application inter-operation capabilities from within the WebKit. This interface is used within
Survey for media captures; the internal methods that accomplish this are in system/survey/
js/odkSurvey.js. Within Tables, this capability is used to navigate between HTML pages
for general content, list views, and detail views (largely via the higher-level methods of the
odkTables wrapper object). As a webpage designer, there is nothing preventing you from
performing media captures from Tables web pages, or from defining custom prompts within
Survey that launch into Tables list views, etc. by leveraging one or the other of the odkSurvey
or odkTables objects.
314 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.13. Injected JavaScript Interfaces
4.13.2 odkData.js
This creates a window.odkData object that wraps calls to the injected odkDataIf Java inter-
face. When loaded inside the App Designer, a mock implementation of the injected interface
is loaded that uses W3C SQL to emulate the injected interface’s capabilities.
This class provides support for asynchronous interactions with a SQL database (internally,
this is implemented via a SQLite database).
The interaction to get the active user’s roles would be:
If the request failed, the errorMsg is the message returned from within the Java layer. As
noted, this is typically the getMessage() of an exception.
Otherwise, the resultObj returned contains information about the outcome. This object is
a wrapper object with accessor methods defined here.
Note:
1. the color information is only present within Tables. It is not computed and returned
within Survey.
2. the display names will need to be localized before use. See the APIs provided by
odkCommon.
4.13.3 odkTables.js
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 315
Chapter 4. Trying It Out
system/tables/js/odkTables.js
It provides methods to open Tables generic web pages and list and detail views. These are
generally just wrappers for calls to odkCommon to invoke the intents for those views.
4.13.4 odkSurvey.js
These files are generally not used by web page developers. They implement the survey form
execution logic and their functions will be broadly covered later in this document.
The reference applications are presented here as real world examples of Data Management
Applications built on the ODK-X platform. The following documentation provides a guided
tour of these application’s workflow and modules, as well as an overview of the internal
structure of its source files. The intention is to provide a useful example for organization’s
to use when creating their own Data Management Applications.
316 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Key Features
The EpiSample application provides a good example of the following ODK-X platform fea-
tures:
• Data Synchronization and Reuse: Collected data is reused to gener-
ate tasks across devices. Shared configuration is set by a supervisor and
synchronized across devices.
• Custom Web Views: Location data is displayed and updated in real
time. Custom data visualizations are used on data entry screens to help
guide collection.
• Complex Workflows: Custom logic is implemented in JavaScript to gen-
erate tasks using collected data and to dynamically launch Survey forms.
• Mapping and Navigation: A map of of homes is generated using col-
lected geo-data. Navigate View is integrated into the workflow to guide
data collectors to homes and launch follow up surveys.
• Adaptability: The application is designed to be flexible to differing usage
scenarios. Different Survey forms can be loaded into the same workflow
to adapt to different data collection needs. Data quantity and location
accuracy requirements can be configured in the app and updated as needed.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 317
Chapter 4. Trying It Out
Installing EpiSample
Source code for this Data Management Application can be found in the malaria-demo branch
of the App Designer repository. As with all of the ODK-X reference applications (and the
ODK-X platform itself), the code is free and open source. Feel free to reuse, modify, or
extend this application and its component parts to suit your organization’s needs.
Note: The EpiSample application (and all other Data Management Applications provided
in these docs) come with a full copy of the Application Designer they were developed in.
After you have have downloaded the application, you can set it up according to the Appli-
cation Designer setup instructions. Similarly, you can push the application to your device
using the Pushing and Pulling Files instructions.
Guided Tour
A walk-through of the features and the application and an overview of how they are imple-
mented is provided in the guide below.
This document guides you through each of the modules of the Geographic Health Survey
App, named EpiSample. They are presented in a logical order, so this guide can be read
from top to bottom to mimic the flow of the application’s use in the field. You can also
skip to the module that most interests you. Each section provides both a brief description
of the purpose and function of the module, as well as an overview of how that functionality
is implemented.
Note: All file paths in this document are inside of the Application Designer directory.
Additionally, all user defined files in a Data Management Application are inside the app/
config/ directory. For convenience this document omits these portions of the file paths.
For example, let us assume I have stored the Application Designer directory on my com-
puter in /home/bobsmith/workspace/app-designer. If this guide were to reference a file
as :assets/index.html that indicates the file located on my computer at /home/bobsmith/
workspace/app-designer/app/config/assets/index.html.
318 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Configuration
Function
The Configuration module is the first screen the user sees after launching the application.
It allows the user to customize the behavior of the application via the Settings Screen. It
also requires the user to specify the location that the surveys will take place through a series
of dropdown menus. Below you can see that the Select button is not revealed until the full
location is specified.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 319
Chapter 4. Trying It Out
The location chosen on this screen is saved and all future modules will make use of that
information.
The Settings screen is a submodule of Configuration. It allows you to customize the behavior
of each module. This includes the acceptable GPS accuracy range, the number of data points
to collect, and the Survey form to use for the Household Data Collection. These settings are
shared across all devices that share ODK Cloud Endpoints.
320 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
The settings can be protected behind a user defined administrative password. If a password
is set, the settings cannot be viewed or modified until it is entered, as shown below.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 321
Chapter 4. Trying It Out
Implementation
This is the home screen first shown when the application is launched, so its HTML file must
be: assets/index.html.
In the <head> of index.html notice that, among the standard ODK-X JavaScript imports
there are also libs/sha256.js and js/epsConfigLib.js. The sha256.js file is used for
protecting the admin password. The epsConfigLib.js file provides an interface for reading
and writing the configuration to the Config table of the database. Since the configuration is
stored in the ODK database, any time the application is synchronized, these settings will be
synchronized with the server. In this way an administrator can remotely control the settings
on all the field workers phones. This custom library is included across all the files in this
application.
The library libs/bootstrap-3.3.7... and the file js/eps_select_place_name.js are
also linked at the bottom of the <body>. Bootstrap is a third party library used for for-
matting and look-and-feel. eps_select_place_name.js implements the dynamic portions
of the user interface of the home screen including: the series of dropdowns that specify the
place name, the Settings button, and the login screen for password protected settings.
The place names dropdowns are populated dynamically by reading from the Place Names
table. These are read via odkData.query and odkData.arbitraryQeury calls. When the
place name is selected, it is stored for later use by the rest of the modules with odkCommon.
setSessionVariable. The Select button launches eps_main_menu.html, which is covered
in the next module.
When the Settings or Login buttons are pressed, they will launch assets/eps_config.
html. This file implements the Settings screen and all its inputs. It links to assets/js/
eps_config.js to handle its logic. This file handles reading the stored configuration from
the database (via epsConfigLib.js), populating that into the form fields, and saving the
new configuration back to the database after the Save button is pressed.
To populate the Choose Form dropdown, the populateChooseFormControl() function in
eps_config.js reads the list of available Survey forms via the odkData.getAllTableIds
function.
Files
• assets/index.html
• assets/js/epsConfigLib.js
• assets/js/eps_select_place_name.js
• assets/eps_config.html
• assets/js/eps_config.js
322 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Forms
None
Database Tables
• Config
• Place name
Main Menu
Function
The Main Menu module is the hub to launch the other modules. The currently selected
place name is displayed along the top for convenience.
The buttons that launch other modules can be dynamically added and removed via the
Settings screen in the Configuration module.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 323
Chapter 4. Trying It Out
Implementation
Files
• assets/eps_main_menu.html
• assets/js/eps_main_menu.js
Forms
None
324 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Database Tables
• Config
• Census
Function
The Village Geographic Survey module is used to gather census data about each household.
It records basic information: a house number, a head-of-household name, and the GPS
coordinates of that household. The house number field is automatically increased with each
saved record.
Recorded households are listed in the bottom portion of the screen. This list includes the
name and house number, an Edit button that allows you to update the record, and an icon
indicating whether the record is Valid or not. The validity of a record is determined by the
accuracy of its GPS coordinates. The thresholds are set in the Configuration module.
The quality of the GPS signal is depicted by the color of the spinner and the specific rating
listed.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 325
Chapter 4. Trying It Out
The above screen on the left depicts a GPS signal that is not accurate enough, and is
displayed in yellow. The screen on the right shows that the icon next to Beth is an I for
326 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
To replace the GPS, the Replace GPS check-mark should be checked, and the Update button
should be pressed.
After all of the household data has been recorded, the user should synchronize their results
to the server (Syncing instructions).
Implementation
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 327
Chapter 4. Trying It Out
Files
• assets/eps_collect.html
• assets/js/eps_collect.js
• assets/js/util.js
Forms
None
Database Tables
• Config
• Census
328 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Function
The Task List Generation module is used to create a randomized task list for each data
collector to perform.
Note: It is important that the Task List Generation module has access to all of the
census data. Every data collector should synchronize their device to the server (Syncing
instructions) so that all the records are available. After that, a synchronization can be
performed to receive the full record set.
The Main, Additional, and Alternate points parameters are set in the Configuration module.
Tip: To allow these fields to be set in this module, set the parameters to zeros in the Config
module.
If there are sufficient records available to meet the parameters, the user can press the Select
button to generate the task list. A progress bar will appear while this process takes place,
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 329
Chapter 4. Trying It Out
followed by a completion notification. This process can take some time if the data set is
large. After the task list is generated it can be synchronized to the server, followed by each
data collector synchronizing to receive the list.
This list of tasks is used to determine where to perform follow up surveys.
Implementation
The file assets/eps_select.html implements the look of this screen. This screen is not
nearly as dynamic as the others, and as such most of the user interface is hard coded here.
This includes the loading screen that appears while the list is being generated.
The file assets/js/eps_select.js reads the Main, Alternate, and Additional point config-
uration and populates the user interface with it. If these are configured to zeros, it will read
in the user defined values for these fields.
When the Select button is pressed, the configuration is used to determine the points to
select for the task list. The third party Async library is used to handle these long running
calculations in the background without locking up the user interface. While they run, the
Please Wait loading screen is shown. The records are read from the Census table with an
odkData.arbitraryQuery call, and then randomized. When this process is complete, the
affected records in the Census table are updated with odkData.updateRow calls.
Files
• assets/eps_select.html
• assets/js/eps_select.js
Forms
None
Database Tables
• Config
• Census
330 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Geographic Navigation
Function
The Navigation Module helps guide a data collector to the households specified in the task
list. The compass, distance, and other navigational indicators will update in real time.
The map will show the points on the task list. The households displayed can be configured
on the Main Menu module to show only Main points, or show Main and Additional and so
on.
When the data collector arrives at the household, they can tap the Arrive button to launch
the Household Data Collection module. Or they can press Cancel at any time to return to
the Main Menu.
Implementation
This view is provided by the ODK-X platform and is not customizable. The view is launched
by a call to odkTables.openTableToNavigateView(...) with query parameters to select
the map markers. The query that selects the map markers is discussed in the Implementation
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 331
Chapter 4. Trying It Out
section. The handling of the results of the Arrive and Cancel button presses are also discussed
in that section.
Files
None
Forms
None
Database Tables
• Census
332 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Function
The Household Data Collection module is an ODK Survey form that is configured in the
Configuration module. This is intended to be provided by the Deployment Architect for
their particular use case, which makes this application flexible to different scenarios. For
example, this could be used for follow up after a Malaria outbreak or it could be adapted to
handle another disease by swapping this form.
The data collected in this form is available in the same database as the rest of the application
and can be used by it.
Implementation
The Household Data Collection form is user configured and not provided in this reference
application. The provided form could be a simple survey or could include complex skip logic,
data quality checks, and customizations to the look-and-feel. Instructions for creating these
forms are available in ODK Survey: Designing a Form guide as well as the ODK XLSX
Converter guide.
Prepopulated forms could also be included with CSV files. See the files in the assets/csv
directory and the assets/tables.init file for examples.
Files
Forms
Database Tables
The Hope Study is a longitudinal clinical trial originally developed at the University of Wash-
ington as a collaboration between the Computer Science and Global Health departments. It
was a randomized control trial studying pregnant, HIV discordant couples and their health
outcomes, and was used for eight months by health workers in western Kenya. More info
about the study can be found in this article. The study was conducted using ODK Collect,
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 333
Chapter 4. Trying It Out
and then ported to the ODK-X tools to demonstrate the features that could be added on
this platform.
Key Features
The Hope Study application provides a good example of the following ODK-X platform
features:
• Data Synchronization and Reuse: The study takes place over a number of months,
revisiting the same clients and reusing previously collected data. Launching the syn-
chronization interface is built into the application’s workflow. Known data is prepop-
ulated into form prompts.
• Custom Web Views: Navigation to the current client and appropriate form is made
simple and easy. Custom data visualizations provide statistics on the full data set.
• Custom Form Linkage: Multiple Survey forms update the same records in a single
database table.
• Complex Form Navigation: Forms will jump between screens based on client eligi-
bility and response validation.
334 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Source code for this Data Management Application can be found in the master branch of the
App Designer repository. It is one of the five demo applications for ODK Tables. As with
all of the ODK-X reference applications (and the ODK-X platform itself), the code is free
and open source. Feel free to reuse, modify, or extend this application and its component
parts to suit your organization’s needs.
Note: The Hope Study application (and all other Data Management Applications provided
in these docs) come with a full copy of the Application Designer they were developed in.
After you have have downloaded the application, you can set it up according to the Appli-
cation Designer setup instructions. Similarly, you can push the application to your device
using the Pushing and Pulling Files instructions.
Guided Tour
A walk-through of the features and the application and an overview of how they are imple-
mented is provided in the guide below.
This document guides you through each of the modules of the Longitudinal Clinic Study
App, named Hope Study. They are presented in a logical order, so this guide can be read
from top to bottom to mimic the flow of the application’s use in the field. You can also
skip to the module that most interests you. Each section provides both a brief description
of the purpose and function of the module, as well as an overview of how that functionality
is implemented.
Note: All file paths in this document are inside of the Application Designer directory.
Additionally, all user defined files in a Data Management Application are inside the app/
config/ directory. For convenience this document omits these portions of the file paths.
For example, let us assume I have stored the Application Designer directory on my com-
puter in /home/bobsmith/workspace/app-designer. If this guide were to reference a file
as :assets/index.html that indicates the file located on my computer at /home/bobsmith/
workspace/app-designer/app/config/assets/index.html.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 335
Chapter 4. Trying It Out
Main Menu
Function
The Main Menu module is the first screen a user sees after launching the application, and
provides a basic choice of the three main workflow options available:
• Screen Female Client: to launch the female client screening form: Screen Client.
• Follow Up with Existing Client: to find the record for an existing client and launch the
appropriate follow up form (the Existing Client List module).
• Send Data: To launch the synchronization interface and sync the database with the
server: Send Data.
Implementation
This is the first screen a user sees, which would usually imply that its html file is assets/
index.html. However, this application is embedded within the larger Tables Sample Appli-
cation, which claims the index.html file. That demo launches assets/hope.html, which
defines this screen. If this application were extracted from this sample application and
deployed on its own, this file would need to be renamed index.html.
336 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
This file creates its HTML <body> dynamically with embedded JavaScript. This JavaScript
defines the three buttons:
• Screen Female Client: Calls odkTables.addRowWithSurvey(...) to launch the screen-
Client form. Notice that the database table being written to is femaleClients which is
shared among other forms. See the Follow Up Forms module implementation details.
• Follow Up with Existing Client: Calls odkTables.openTableToListView(...) to
launch the Existing Client module.
• Send Data: Calls odkCommon.doAction(...) to launch the SyncActivity. This is the
same functionality as pressing the sync button in the upper right of the screen, but
with two advantages.
1. The call is embedded within the custom workflow of the application so the user
can be instructed to use it at the appropriate time.
2. The doAction function supports the Action-Callback workflow, which means fur-
ther actions could be triggered after synchronization is completed.
Files
• assets/hope.html
Forms
None
Database Tables
None
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 337
Chapter 4. Trying It Out
Screen Client
Function
The Screen Client form is used to conduct an interview with a potential new client. It
provides a script for the interviewer and ask questions relating to the potential client’s
eligibility along with some basic demographic information. If the client is eligible, it asks for
consent and instructs the interviewer in the process of randomizing the client into Hope or
the control group.
Implementation
338 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Data is validated with the required column and select_multiple prompts define their choices
with links in the values_list column.
The choices worksheet defines all the options for each select_multiple prompt.
The settings worksheet defines the form_id and the table_id to store form instances. Notice
that the table_id is femaleClients, which will also be the table_id for other forms in the
follow up forms.
The model worksheet is used to specify the data model for the femaleClients table. See the
XLSX Converter Reference for more details
Files
• tables/femaleClients/forms/screenClient.xlsx
Forms
Database Tables
• femaleClients
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 339
Chapter 4. Trying It Out
Send Data
Function
This module is the synchronization interface, see the Services User Guide. It is included
here because it is embedded into the Hope Study workflow. After registering new clients
or interviewing existing clients, this module is used to submit that data. Also, before work
is started each day, this should be used to ensure the latest forms from all the clients are
available on the device.
Implementation
Files
None
340 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Forms
None
Database Tables
None
Function
The Existing Client module is used to perform follow up interactions with existing clients,
or to view statistics about the current client pool. It displays a list of all of the currently
registered clients with their client ID, age, and randomization status. This list will grow to
be quite long, so searching by client ID is supported. Typing in the desired client ID will
leave only the matching client in the list below. If you were to search for client ID 44176,
the interface would update as shown in the following image.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 341
Chapter 4. Trying It Out
Tapping a client in the list will launch the Client Details module.
If a new client needs to be added, bypassing the screening process (for example, if a registered
client is scheduled for an interview but they are not showing up in the system because a
worker didn’t synchronize recently enough) the Add Client button will launch the survey:
Add Client Brief. This form contains a brief questionnaire (a subset of the full Add Client
form from the Screen Client module) that writes to the same database table (femaleClients).
After the form is saved it will appear on the Existing Clients list and a follow up survey can
be performed.
Pressing the Graph View button will launch the Graph View module.
Implementation
342 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
list item is coded to call the handleClick(...) function if they are pressed, which launches
the Detail View of the selected record with odkTables.openDetailView(...).
The render() function also creates the Add Client and Graph View buttons.
These are hard coded to launch odkTables.addRowWithSurvey(...) and odkTables.
openTableToListView(...) respectively. This particular graph view is a special case of
a List View, and the query provided (selecting every client) provides the data the graph will
use to render its visualizations. Each of these calls modifies or reads the femaleClients table.
The survey that is launched by the Add Client button is defined by tables/femaleClients/
forms/addClient.xlsx. It is quite short and simple, and is a subset of the form described
in the Screen Client implementation details.
The function getResults() implements the search functionality. It queries the database
with odkData.query(...), searching for the provided client ID. If that client is found, it
opens up a new instance of this module with the same query, ensuring the List View will
only show the desired client. Opening a new client, rather than updating the current list,
ensures that when the user presses the back button they will return to the current instance
of the module with the full list of clients instead of returning to the home screen.
Files
• tables/femaleClients/html/femaleClients_list.html
• tables/femaleClients/js/femaleClients_list.js
• tables/femaleClients/forms/addClient.xlsx
Forms
Database Tables
• femaleClients
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 343
Chapter 4. Trying It Out
Client Details
Function
The Client Details module is a hub to perform follow up and additional data collection for
the selected client. The three main data points about the client are displayed at the top:
client ID, age, and randomization status. The follow up forms are organized into Client
Forms (forms pertaining to the female client) and Partner Forms (forms pertaining to the
female clients partner). Tapping the desired section will expand it to display the collection
options.
The Home Locater button launches the Home Locater module. The rest of the forms are
discussed in the Follow Up Forms section.
Implementation
344 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
The call that launched the view provided a query as a parameter that selects which record will
be displayed in the Detail View. This record is retrieved with the odkData.getViewData(.
..) call. The returned record is used to fill in the basic info at the top of the screen, and
then the Client Forms and Partner Forms are created. These buttons link to the Follow Up
Forms using odkTables.editRowWithSurvey(...) and odkTables.addRowWithSurvey(..
.) API calls. All the buttons in the Client Forms section use the table ID femaleClients and
the client ID of the selected record, while all the buttons in the Partner Forms section use
the table ID maleClients and the male client ID (read from the selected record).
Additionally, the Home Locater module is launched with the Home Locater button using an
openTableToListView(...) call.
Files
• tables/femaleClients/html/femaleClients_detail.html
• tables/femaleClients/js/femaleClients_detail.js
Forms
None
Database Tables
• femaleClients
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 345
Chapter 4. Trying It Out
Home Locater
Function
The Home Locater module is used to navigate to the client via provided instructions and
waypoints on a map. The main screen shows you this list of instructions, including the
means of transportation to travel between each one (such as walking or Tuk-tuk). These
instructions are populated by pressing the Add Waypoint button. This button launches a
survey that records the transportation type, GPS coordinates, and enters it in its proper
place in the list.
A button is also provided to launch a Map View.
346 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
This map view shows the same list of instructions on the top, but uses most of the screen
real-estate to show the waypoint markers on the map. Tapping a map marker highlights the
instruction. Tapping the instruction on the list opens a Detail View of the instruction.
Implementation
The Home Locater module functions almost as a miniature version of the rest of the appli-
cation. The root List View, much like the Existing Client List module, receives its list from
the caller query via the odkData.getViewData(...) call and uses that to render a list of
clickable items that will launch the Detail View. The Detail View shows to basic data about
the record, similarly retrieved with the odkData.getViewData(...) call.
The Add Waypoint button acts similarly to the Add Client button in the Existing Clients
module, but launches the Home Locater form. This form contains a few basic text and
select_one prompts, as well as a geopoint prompt to collect location data. The properties
worksheet is what makes this form distinct from the other forms in this application. It
specifies all the mappings to set up the Map View, such as the mapListViewFileName and
the defaultViewType as a MAP.
The tables/geopoints/html/geopoints_map_list.html and tables/geopoints/js/
geopoints_map_list.js files fine a basic list that should be recognizable in structure to
the other List View files. However, it has added logic to handle the ordering of the list items
basic on selected points on the map in the render(...) function.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 347
Chapter 4. Trying It Out
Files
• tables/geopoints/html/geopoints_list.html
• tables/geopoints/js/geopoints_list.js
• tables/geopoints/html/geopoints_detail.html
• tables/geopoints/js/geopoints_detail.js
• tables/geopoints/html/geopoints_map_list.html
• tables/geopoints/js/geopoints_map_list.js
• tables/geopoints/forms/geopoints.xlsx
Forms
Database Tables
• geoopoints
348 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Follow Up Forms
Function
The follow up forms are the bulk of the longitudinal study. After clients are screened and
entered into the study, six week and six month follow ups will take place. Furthermore, their
partner may be screened to enter the study with them, and also receive a six month follow
up.
Each of these are launched from the Client Details module. They are survey forms that
provide the interviewer with a script and ask detailed medical questions. Some previously
collected data will be prepopulated in the forms prompts.
Implementation
The two Client Forms both read and write from the femaleClients table (as can be seen
on the settings worksheet of both forms). This is true for both Partner Forms and the
maleClients table as well.
These surveys are similar in structure to the initial Screen Client form. There is basic navi-
gation logic via if and other condition clauses. Simple data collection occurs with select_one,
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 349
Chapter 4. Trying It Out
select_multiple, integer, decimal, text, and date prompts. Interviewer scripts are provided
with note prompts. The client ID is marked as necessary with the required: column, how-
ever, this field should always be prepopulated in follow up forms. This is because the form
is modifying an existing record in the database, and the field already has a value. In general
this could be changed, though in this workflow this would be rare. The model worksheet
provides the linkage with the database table.
There are also files to define List Views and Detail View for the male partners, even though
they are not reachable through the normal workflows. These can be launched by opening
the table directly via the Tables Manager screen.
Files
• tables/femaleClients/forms/client6Week.xlsx
• tables/femaleClients/forms/client6Month.xlsx
• tables/maleClients/forms/screenPartner.xlsx
• tables/maleClients/forms/partner6Month.xlsx
Forms
Database Tables
• femaleClients
• maleClients
350 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Graph View
Function
The Graph View module is a simple pair of pie chart displaying statistics about the current
client pool. The first pie chart, titled Intervention Arms, displays the ratios of clients in
each of the intervention arms: Hope, Control, or Ineligible. The second pie chart, titled HIV
Status, shows the ratios of HIV+, HIV-, and untested respondents.
This view is currently displaying static data and does not reflect the true values in the
database. This was done for simplicity in showing Tables features in the Sample Application:
showing how a graph might look, despite not having real patient data initialized on the
device. However, with a little a couple calls to the database and a little more JavaScript
implementing the math, this could be updated dynamically.
Implementation
The implementation of this module is less interesting considering it does not show real data.
However, it is still a useful display of how complex data visualizations can be rendered on
the device, without outside processing or internet access. The file tables/femaleClients/
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 351
Chapter 4. Trying It Out
html/graph_view.html makes use of the third party D3 JavaScript library to draw the pie
charts.
To ratios are fed into the graph rendering in the display(...) function. If these were
replaces with variables, and those variables were populated by summing up results of calls to
the database with odkData.query(...) and odkData.arbitraryQuery(...), the graphs
would be update according to the real data. This can be performed by the diligent reader
as an exercise.
Files
• tables/femaleClients/html/graph_view.html
Forms
None
Database Tables
None
The Cold Chain application is a health facility maintenance application originally developed
at the University of Washington in collaboration with PATH and Village Reach. It is a
prototype meant to be deployed at national scale to manage refrigerator inventory and
maintenance at health facilities across the country. The purpose of this is to ensure vaccines
are kept at sufficiently cold temperature and maintain their efficacy.
352 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Key Features
The Cold Chain application provides a good example of the following ODK-X platform
features:
• Data Synchronization and Reuse: The health facility, refrigerator, and
maintenance log data set is stateful rather than the traditional model of
being actively collected. If a refrigerator breaks, it is synchronized and the
state is updated so other users can see this state change.
• Custom Web Views: Finding and viewing the details of health facilities,
refrigerator models, and individual refrigerators is completely customized
to the needs of this application. Custom visualizations provide statistics on
the full data set, such as refrigerator age.
• Complex Workflows: This application does not follow the traditional
data collection model. A custom workflow for managing and repairing in-
ventory is implemented in JavaScript.
• Mapping: An up to date map of health facilities is rendered from the data
set, and is organized into regions, to provide context for where problems
may occur and to help navigate to different sites.
• Advanced Form Design: The Survey forms use database queries, choice
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 353
Chapter 4. Trying It Out
Source code for this Data Management Application can be found in the cold-chain-demo
branch ofthe App Designer repository. As with all of the ODK-X reference applications
(and the ODK-X platform itself), the code is free and open source. Feel free to reuse,
modify, or extend this application and its component parts to suit your organization’s needs.
Warning: This application requires user and group permissions to be set up on the
server before use. Please review the documentation for Data Permission Filters and Sync
Endpoint LDAP.
You will need at least one user that is a table administrator, and to set up the groups:
• REGION_NORTH
• REGION_CENTRAL
• REGION_CENTRAL_EAST
• REGION_CENTRAL_WEST
• REGION_SOUTH
• REGION_SOUTH_EAST
• REGION_SOUTH_WEST
You should add users to the various groups, and set their default group as the region
where they can edit records. For example, user dana might belong to groups synchro-
nize_tables, region_south and region_south_east and have their default group set to re-
gion_south_east. In this scenario data can modify data in the group region_south_east
and can see but not modify the rest of region south (namely, region_south_west).
Note: The Cold Chain application (and all other Data Management Applications provided
in these docs) come with a full copy of the Application Designer they were developed in.
After you have have downloaded the application, you can set it up according to the Appli-
cation Designer setup instructions. Similarly, you can push the application to your device
354 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Guided Tour
A walk-through of the features and the application and an overview of how they are imple-
mented is provided in the guide below.
This document guides you through the Inventory Management and Maintenance App, named
Cold Chain. This application is stateful and does not have a single workflow to follow. There-
fore it is organized by area of interest, with each classification broken down into different
workflows and modules contained within it. Each individual module contains both a brief
description of the purpose and function of the module, as well as an overview of how that
functionality is implemented.
Note: All file paths in this document are inside of the Application Designer directory.
Additionally, all user defined files in a Data Management Application are inside the app/
config/ directory. For convenience this document omits these portions of the file paths.
For example, let us assume I have stored the Application Designer directory on my com-
puter in /home/bobsmith/workspace/app-designer. If this guide were to reference a file
as :assets/index.html that indicates the file located on my computer at /home/bobsmith/
workspace/app-designer/app/config/assets/index.html.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 355
Chapter 4. Trying It Out
Function
The initial data set is not part of the actual workflow of the application, but is described here
to provide context for how this application is set up and how it might be used in the field.
This initial data set is the full list of health facilities, refrigerators, and refrigerator types
that currently exist in the health system to be modeled. The initial Deployment Architect
could choose to collect this data via survey forms within the application itself (which are
already provided, and used for adding data as the current state changes), but if they already
have a database of health facility inventory, this might be the more convenient method.
For demonstration purposes the provided default data set also has maintenance logs that
are seeded into the database.
Implementation
The initial data set is codified in .csv files specified in assets/tables.init that will
be imported into the database on the initial startup. Instructions for how this works are
available here: Configuring an App at Startup.
356 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Each .csv matches the schema of its corresponding table in the database. The appropriate
values are filled in for each data field. Additionally, the _group_modify, _group_privileged,
and group_read_only columns include the group names to properly organize the data. The
full set of custom groups in the provided data set include:
• REGION_NORTH
• REGION_CENTRAL
• REGION_CENTRAL_EAST
• REGION_CENTRAL_WEST
• REGION_SOUTH
• REGION_SOUTH_EAST
• REGION_SOUTH_WEST
Note: The group GROUP_ADMIN is also used, but is a default group provided to all
Data Management Applications.
The _group_priviledged column should be set to GROUP_ADMIN for all rows in all
tables. This provides full access to administrators to modify any data they choose.
In refrigerator_type.csv the columns _group_modify and _group_read_only should
both also be set to GROUP_ADMIN to restrict changes to this protected table. In
health_facility.csv and refrigerator.csv the _group_modify column should be set to
the most specific group the item belongs to, while the _group_read_only column should be
set to the broader region. For example, a health facility in the South East region should have
its _group_modify set to GROUP_REGION_SOUTH_EAST and its _group_read_only
column set to GROUP_REGION_SOUTH. This will allow users in the South East region
to update this facility, but only view facilities in the South West region.
Note: This group organization and permissions set up is specific to the default data set
provided with the reference application. However, this is not a requirement of the ODK-X
tools. Groups could be set up to modify regions and view everything, or only read the region
they belong to, or even restrict some users from modifying anything and only reading data.
See Data Permission Filters for more details.
The JavaScript is configured to expect these groups and this set up. To use the application
you will need to configure your ODK Sync Endpoint to have at least one table administra-
tor. You should also add users to the various groups, and set their default group as the
region where they can edit records. For example, user dana might belong to groups syn-
chronize_tables, region_south and region_south_east and have their default group set to
region_south_east. In this scenario data can modify data in the group region_south_east
and can see but not modify the rest of region south (namely, region_south_west).
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 357
Chapter 4. Trying It Out
Files
• assets/tables.init
• assets/csv/health_facility.csv
• assets/csv/refrigerators.csv
• assets/csv/refrigerator_types.csv
• assets/csv/refrigerator_types/...
Forms
None
Database Tables
• Health Facility
• Refrigerators
• Regrigerator Types
358 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Authentication
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 359
Chapter 4. Trying It Out
Function
The Authentication screen is the gateway to the Cold Chain application. The application
filters data and restricts access based on the authenticated user’s group and assigned permis-
sions. Therefore a user with a recognized set of permissions must be authenticated before the
Cold Chain application can be used, and the application will lock itself until that condition
is met.
The application checks the authenticated user’s credentials at startup, so if a valid user is
already logged in, this screen will be completely bypassed. If not, the screen shown to the
left above is shown. When you press the Log In button, the Change User screen is directly
launched. This allows you to authenticate as your desired user. After you have authenticated,
you can press back until you return to the Cold Chain application. The same authentication
check will occur, and either valid credentials will be found or the same Authentication screen
will be shown.
If the authenticated user is an administrator, the Administrator Options will be shown. If the
authenticated user is a normal data synchronizer assigned to a valid group, the appropriate
Regions screen will be shown.
Implementation
This screen is the first view launched when the application is opened, which means it must
start with assets/index.html. This contains only few <div> elements that will be filled in
by assets/js/menu.js. This file also makes use of the library: assets/js/util.js.
The Cold Chain application supports both English and Spanish locales, and the first thing
index.html does is check the current locale, and use it to localize text throughout the page
with the API odkCommon.getPreferredLocale() and odkCommon.localizeText(...).
Next the JavaScript checks for a query parameter in the URL. Throughout this application
arguments and query parameters will be passed across files as URL parameters. However,
since this is the first launch, this argument will be null, which will trigger the check for the
user’s default group: odkData.getDefaultGroup(...).
Depending on the returned default group, the next action is:
• Valid Group: the corresponding Regions page is shown.
• Table Administrator, the Administrator Options page is shown.
• Null: the user is either anonymous or has not been set up with a default group. The
user is prompted to authenticate with a different identity.
• Anything else: The user does not have privileges within this application and is
prompted to authenticate with a different identity.
360 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
In either of the bottom two options, the log in screen is shown. The Log In button launches
an intent to the log in screen of ODK Services. The API odkCommon.doAction(...) takes
the intent as an argument, which should be pointed at the SyncActivity. To specifically get
the log in screen the bundle should include the showLogin value set to true.
When the user returns from authentication this process will repeat until a Valid Group or a
Table Administrator is found.
Files
• assets/index.html
• assets/js/menu.js
• assets/js/util.js
Forms
None
Database Tables
None
Regions
Regions are tiered geographic groupings that contain a list of health facilities. The Cold
Chain application is intended to scale to national deployments, and support for regions
allows the large data set to be subdivided into manageable pieces. Furthermore, users in
different regions are restricted to viewing and modifying data in their region. This has the
dual advantage of clearing up the extra clutter that is not relevant to the user, and preventing
them from making changes to data they should not have access to.
Regions affect health facility, refrigerator, and maintenance data. Every row in these three
tables will be tied to a particular region. The refrigerator type data is not tied to particular
regions.
Regions have multiple tiers. For example, the Balaka region is contained inside the South
East Region, which is contained in the larger South region. This example has three tiers,
but this is not required. The Chitipa region is contained in the North region (there is no
East/West subdivision).
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 361
Chapter 4. Trying It Out
Selecting a Region
362 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Function
The Region Selection screen is the first screen you will encounter after being authenticated
and granted access. This will differ based on the authenticated user’s particular group. For
example, the user authenticated in the image to the left above has a default group of RE-
GION_SOUTH_EAST and the user in the image to the right above has a default group
of REGION_NORTH. This is the same first screen shown to each user, it is populated
to fit their location.
Each button in the list signifies a smaller region contained in the lager region, and the list
is generated dynamically based on the region shown. The number of tiers needed to get to
the smallest region level will depend on the default group of the authenticated user and the
number of tiers it contains.
Implementation
This screen is shown when assets/index.html and assets/menu.js execute the au-
thentication code and find a user with a valid region. This will trigger the function
showSubregionButtonsAndTitle(...) in menu.js, which handles the tiered subregions and
creates a list of buttons based on the regions one tier below the authenticated users default
group region. The default group region is parsed by the util.getMenuOptions(...) func-
tion in assets/util.js. This default group string might, itself, contain its subgroups if the
group is a higher tier. If that is the case those subregions will be listed as the buttons, and
when pressed they will relaunch this screen with a URL parameter indicating the subregion
as the new focus region. See addMenuButton(...) in menu.js to see how index.html is
relaunched with a new parameter.
If the sub regions are not found by the above method, then the database is queried for the
sub regions: util.getDistrictsByAdminLevel2(...) calls odkData.arbitraryQuery(..
.) and queries the health_facility table.
When leaf regions or regions at the child tier that contain Health Facilities are reached, the
region buttons will launch the Region Menu screen.
Files
• assets/index.html
• assets/js/menu.js
• assets/js/util.js
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 363
Chapter 4. Trying It Out
Forms
None
Database Tables
• Health Facility
Region Menu
Function
The region menu is the hub of most of the activities you might want to perform. It contains
buttons to:
• View All Health Facilities: Launch a list of health facilities located in this region.
• Filter Health Facilities By Type: Launch a menu listing types of health facilities.
• View All Refrigerators: Launch a list of refrigerators located in health facilities in this
region.
364 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
• View All Refrigerators Needing Service: Launch a list of refrigerators located in health
facilities in this region that are marked as needing service. This is particularly useful
for a maintenance worker looking for refrigerators to fix, or for administrators looking
to see how many refrigerators are in need of service in a particular region.
• View Refrigerator Models: Launch a list of refrigerator types contained in the region.
Implementation
The HTML file assets/leafRegion.html contains all five button definitions as they are
the same no matter what region is selected or user is authenticated. The corresponding
JavaScript file assets/js/leafRegion.js localizes the strings, fills in the region name on
top (from util.getQueryParameter(...)), and adds actions to each button.
The actions are the same for each region, but the query parameters are passed along to
the next view. The are generated with util.getKeysToAppendToColdChainURL(...). The
actions are:
• View All Health Facilities: Open the Lists of Health Facilities to the Map View with
odkTables.openTableToMapView(...). The query specifies to select all rows match-
ing the current region from the health_facility table.
• Filter Health Facilities By Type: Open the Lists of Health Facilities to the type filtered
navigation menu with odkTables.launchHTML(...). This API is used for customized
web views.
• View All Refrigerators: Open the Lists of Refrigerators with odkTables.launchHTML(.
..). This does not take a query as a parameter as a normal List View would, but rather
performs its own queries as needed based on the URL parameters passed and the user
interactions on the page.
• View All Refrigerators Needing Service: Same as above but with appropriate URL
parameters and HTML file arguments.
• View Refrigerator Modesl: Open the Lists of Refrigerator Types with odkTables.
openTableToListView(...)
Files
• assets/leafRegion.html
• assets/js/leafRegion.js
• assets/js/util.js
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 365
Chapter 4. Trying It Out
Forms
None
Database Tables
None
Health Facilities
Health Facilities in the Cold Chain application contain the state of real world health facilities.
They include general information about their status, power, location, and vaccine stock, as
well as an active record of their refrigerator inventory. The intention of this application is
that a user or administrator could navigate the application to a health facility and learn its
basic advantages and disadvantages, and if it needs attention.
366 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Function
The list of health facilities is presented as a Map View. The list portion of the view provides
a clickable list of health facilities: clicking a facility will launch the Health Facility Menu.
The map portion renders that list according to the location data stored in those facilities.
This can be used to navigate to facilities or to find a facility in which you may know the
location better than the name.
• View All Health Facilities: This screen is reached by pressing the View
All Health Facilities button on the Region Menu page. It lists every health
facility located inside of the specified region. It is pictured above.
• Filter Health Facilities By Type: This screen is reached by pressing the
Filter Health Facilities by Type button on the Region Menu page. It lists
each type of health facility contained in the region, and a the number of
health facilities that match the type:
When one of those health facility types is selected, a list similar to the
full health facility list above is rendered, but only containing health
facilities within the specified region that match the chosen type. The
image below is the list of Regional Vaccine Store type facilities in the
Balaka region:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 367
Chapter 4. Trying It Out
Implementation
• View All Health Facilities: This path to the health facilities list launches tables/
health_facility/html/hFacility_list.html. It contains a <div> for the wrap-
per and for the list of facilities, which is populated with tables/health_facility/
js/hFacility_list.js. This JavaScript file follows a standard List View pattern:
it retrieves the query data with odkData.getViewData(...), creates list items for
each of the rows, adds them to the HTML view, includes a link to odkTables.
openDetailView(...) for each list item, and handles paging with resumeFn(...)
called with an index.
• Filter Health Facilities By Type: This path launches assets/
filterHealthFacilitiesByType.html. It contains <div> tags for buttons
that will be filled in by assets/js/filterHealthFacilitiesByTypes.js. This
file uses the provided district to construct a query, which is executed by util.
getFacilityTypesByDistrict(...) in assets/js/util.js and calls odkData.
arbitraryQuery(...). This query runs on the health_facility table and finds all
facilities in the region, groups them by type, and returns the count in each type. These
results are then fed back into filterHealthFacilitiesByType.html which creates
the buttons. Each button, if pressed, will use odkTables.openTableToMapView(...)
to launch the same hFacility_list.html used above, but with the query narrowed
by facility type.
368 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Files
• tables/health_facility/html/hFacility_list.html
• tables/health_facility/js/hFacility_list.js
• assets/filterHealthFacilitiesByType.html
• assets/js/filterHealthFacilitiesByType.js
• assets/js/util.js
Forms
None
Database Tables
• Health Facility
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 369
Chapter 4. Trying It Out
Function
The Health Facility Menu is a Detail View that lists all the information about the chosen
health facility. This includes Basic Facility Information, Power Information, Location In-
formation, and Stock Information. If any of this information is out of date or needs to be
modified, the Edit Health Facility button launches an ODK Survey form that allows you to
modify these values:
370 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
The prompts in this form will be prepopulated with the values shown on the menu page. All
correct values can be safely skipped, so you can edit only the fields that need to be corrected.
The menu also provides a button to view the Refrigerator Inventory. This will launch the
list of refrigerators contained within this health facility.
The Add Refrigerator button will launch a Survey form to create a new refrigerator. When
the form is completed, this refrigerator will automatically be added to the inventory of this
health facility and organized into the containing region.
Implementation
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 371
Chapter 4. Trying It Out
the form Health Facility and pointed at this particular row ID. This form can be viewed
at tables/health_facility/forms/health_facility/health_facility.xlsx. It con-
denses its prompts into only a few screens with extensive use of begin screen and end screen
clause values. Notice that all text in this form also has Spanish translations provided. The
form contains many static select_one prompts with their choices defined in the choices
worksheet. Additionally, the Admin Region select_one_dropdown has its choices populated
dynamically from a query defined in the queries worksheet. This list is then filtered by the
value in the choice_filter column back in the survey worksheet. The settings worksheet con-
tains the supported languages in addition to the normal settings. The properties worksheet
defines the default Detail View, List View, and Map View files and settings. The model links
the region levels from to the database.
If the Refrigerator Inventory button is pressed, odkTables.launchHTML(...) is called to
launch the Lists of Refrigerators screen with this health facility as the filter.
If the Add Refrigerator button is pressed, odkTables.addRowWithSurvey(...) is called
for the Refrigerators form. The permission and group values of the current health facil-
ity are passed in as arguments as well, in order to create this new refrigerator with the
same values. This form can be viewed at tables/refrigerators/forms/refrigerators/
refrigerators.xlsx. It is similar to the Health Facility form: short and compressed into a
small number of screens. The refrigerator model and health facility choices are both queried
from the database (see the queries worksheet). The necessary fields are linked in the models
worksheet. The choices, properties, and settings worksheets are similar to those found in the
Health Facility form, but with their own values.
Files
• tables/health_facility/html/health_facility_detail.html
• tables/health_facility/js/health_facility_detail.js
• assets/js/util.js
• tables/health_facility/forms/health_facility/health_facility.xlsx
• tables/health_facility/forms/health_facility/regions2-3.csv
• tables/refrigerators/forms/refrigerators/refrigerators.xlsx
• tables/refrigerators/forms/refrigerators/refrigerators.xlsx
• tables/refrigerators/forms/refrigreators/regions1-2.csv
• tables/refrigerators/forms/refrigreators/regions2-3.csv
Forms
372 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Database Tables
• Health Facility
• Refrigerators
Refrigerators
Refrigerators are a key element of the Cold Chain application. Their working status is
necessary for keeping vaccines cold and effective. This application focuses on providing easy
access to the working status of lists of refrigerators organized in a multitude of different
ways. It also tracks basic information about the refrigerator, such as its age and model.
Refrigerators belong to Health Facilities and they contain Maintenance Records.
Lists of Refrigerators
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 373
Chapter 4. Trying It Out
Function
A Refrigerator List contains a clickable list of refrigerators: clicking the refrigerator will open
the Refrigerator Menu. The list can be searched by the refrigerator’s ID, the tracking ID,
the health facility name, or the health facility ID:
The search string does not need to be a perfect match. Substrings and approximate matches
can be searched and all matching records will be displayed. For example, if you searched
225 then you might get back refrigerators with ID 22500172, 22500035, and 22500032.
This page is paginated by default to 10 refrigerators per page. This can be adjusted to 20,
50, 100, or 1000 by selecting the option from the drop menu. To navigate between pages of
refrigerators, use the Next and Prev buttons.
Tapping the Edit button will launch the full Survey form for this refrigerator. Each field
will be prepopulated with the values shown in the menu, so that only the values that are
incorrect need to be filled in.
These lists can be organized a number of ways:
• By Region: This lists all refrigerators in the region and is launched by pressing the
View All Refrigerators button on the Region Menu. This is what is shown above.
• By Health Facility: This lists all refrigerators in a particular health facility. It is
launched by pressing the Refrigerator Inventory button on the Health Facility Menu.
374 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
• By Type: This lists all refrigerators in a particular region organized by type. This is
launched by pressing the View All *Model ID* Refrigerators button on a Refrigerator
Type Menu.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 375
Chapter 4. Trying It Out
• Needing Service: This lists all refrigerators in a particular region that are in need
of service. This is launched by pressing the View All Refrigerators Needing Service
button on the Region Menu.
Implementation
The refrigerator lists launched By Region, By Health Facility, and By Type all use
config/tables/refrigerators/html/refrigerators_list.html and achieve their differ-
ent lists by passing different query parameters. This file defines the search form, the
pagination drop menu, and the JavaScript functions to call on button presses. All the
rest of the user interface is added dynamically in config/tables/refrigerators/js/
refrigerators_list.js. However, this file only handles populating the user interface
elements defined in refrigerators-list.html. All of the logic is handled by the shared
library file config/assets/js/list_view_logic.js. This file is discussed in the following
subsection: The list_view_logic.js library.
The refrigerator list launched by Needing Service uses config/tables/refrigerators/
html/refrigerators_service_list.html and config/tables/refrigerators/js/
refrigerators_service_list.js, but these files work nearly identically to their
refrigerators_list.*. The only difference is the listQuery variable that defines the SQL
query to be run. Both files join the Refrigerators, Health Facilities, and Refrigerator Types
tables in order to support filtering and sorting on facility name, facility ID, tracking ID, and
refrigerator ID (see the searchParams variable). The refrigerators_service_list.js
376 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
This library handles the queries, ordering, search, and pagination for all the search List Views
in the Cold Chain application. In this section the calling files are refrigerators_list.js
and refrigerators_service_list.js, but there are others as well. For the rest of this
section I will refer to these as the caller.
When the caller is initializing, it will use the set functions to build state. First the table ID
must be set with setTableId(...). Then the query parameters with setListQuery(...
), setListQueryParams(...), and setSearchParams(...). And finally the user interface
elements need to be supplied with setListElement(...), setSearchTextElement(...),
and so on, to allow the list_view_logic.js file to read and write to them directly.
After state is initialized, the resumeFn(...) can be called. This function uses session vari-
ables (via odkCommon.setSesionVariable(...) and odkCommon.getSessionVariable(..
.) to track search terms, query keys, and pagination indices. It uses these values to build
SQL queries and then runs them with a series of odkData.arbitraryQuery(...) commands
to count the matching records and then retrieve the appropriate subset to display on the
page. The results of that final query are used to create the list elements and populated them
onto the page. Each list element contains a odkTables.openDetailView(...) command
embedded in it. This works in a generic file like this because the default Detail View for
each of these tables has been set in the settings page of the corresponding .xlsx file.
There is also more complex logic to handle the Edit and Delete buttons. The file must ensure
the authenticated user has the requisite permissions for each record before displaying the but-
ton. If they do, and the button is pressed, the functions odkTables.editRowWithSurvey(.
..) and odkData.deleteRow(...) are called, respectively.
There are controls for the Next and Prev navigation buttons that ensure they do not go
beyond the bounds of the full result set. Each time they are pressed, the resumeFn(...)
is called again to re-query and redraw the results. Similarly, the Search button parses the
text of the search, constructs a new query, and calls resumeFn(...). All of these functions
communicate their parameters for the redraw through session variables.
Files
• config/tables/refrigerators/html/refrigerators_list.html
• config/tables/refrigerators/js/refrigerators_list.js
• config/tables/refrigerators/html/refrigerators_service_list.html
• config/tables/refrigerators/js/refrigerators_service_list.js
• config/assets/js/list_view_logic.js
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 377
Chapter 4. Trying It Out
Forms
None
Database Tables
• Refrigerators
• Health Facilities
• Refrigerator Types
Refrigerator Menu
378 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Function
The Refrigerator Menu is a Detail View that shows all the information about the particular
refrigerator. Notable fields include Status and Date Serviced.
It also contains a number of buttons:
• View Model Information: Launches the corresponding Refrigerator Type Menu.
• View Facility Information: Launches the Health Facility Menu of the facility this
refrigerator belongs to.
• Add Maintenance Record: Launches a Survey form to add a new Maintenance Records.
This record will be associated with this refrigerator and appear in future logs. This is
meant to be filled out after a refrigerator is serviced.
• View All Maintenance Records: Launches a Lists of Maintenance Records of all records
associated with this particular refrigerator. It serves as a full service history of this
unit.
• Edit Refrigerator Status: Launches a Survey form that modifies only the service related
details of this refrigerator. To be pressed when this refrigerator breaks or receives
maintenance.
• Edit Refrigerator: Launches the full Survey form for this refrigerator. Each field will
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 379
Chapter 4. Trying It Out
be prepopulated with the values shown in the menu, so that only the values that are
incorrect need to be filled in.
Implementation
380 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Files
• tables/refrigerators/html/refrigerators_detail.html
• tables/refrigerators/js/refrigerators_detail.js
• config/assets/js/util.js
• tables/maintenance_logs/forms/maintenance_logs/maintenance_logs.xlsx
• tables/refrigerators/forms/refrigerator_status/refrigerator_status.xlsx
• tables/refrigerators/forms/refrigerators/refrigerators.xlsx
Forms
Database Tables
• Refrigerators
• Health Facility
• Refrigerator Types
• Maintenance Logs
Maintenance Records
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 381
Chapter 4. Trying It Out
Function
382 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Implementation
Files
• tables/maintenance_logs/html/maintenance_logs_list.html
• tables/maintenance_logs/js/maintenance_logs_list.js
• config/assets/js/list_view_logic.js
Forms
None
Database Tables
• Maintenance Logs
• Refrigerators
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 383
Chapter 4. Trying It Out
Function
The Maintenance Record Menu is a Detail View that lists the full account of the service,
including the Reason Not Working, the Date Serviced, Spare Parts, and other details.
It also includes an Edit Log button, which launches the Survey form for this maintenance
record. Each field will be prepopulated with the values shown in the menu, so that only the
values that are incorrect need to be filled in.
Implementation
384 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Refrigerators table. The resulting data sets are combined to fill in the display fields on the
detail view.
The Edit Log and Delete Log buttons are dynamically hidden or shown depending on the
privileges of the authenticated user.
If the Edit Log button is pressed, the Maintenance Logs form is launched with odkTables.
editRowWithSurvey(...). The forms .xlsx file is located at tables/maintenance_logs/
forms/maintenance_logs/maintenance_logs.xlsx. This form is discussed in the refrig-
erator menu implementation section under the Add Maintenance Record bullet.
If the Delete Log button is pressed, odkData.deleteRow(...) is called to remove the record
from the database.
Files
• tables/maintenance_logs/html/maintenance_logs_detail.html
• tables/maintenance_logs/js/maintenance_logs_detail.js
• assets/js/util.js
• tables/maintenance_logs/forms/maintenance_logs/maintenance_logs.xlsx
Forms
Database Tables
• Maintenance Logs
• Refrigerators
Refrigerator Types
Refrigerator Types represent the different models of refrigerators available. This is convenient
for adding a new refrigerator to a health facility, as the model will already include information
about the refrigerator that might not be obvious to the worker installing the unit. It also
provides an easy reference if spare parts are needed or the model itself is needed for any
reason.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 385
Chapter 4. Trying It Out
Function
386 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Implementation
Files
• tables/refrigerator_types/html/refrigerator_types_list.html
• tables/refrigerator_types/js/refrigerator_types_list.js
Forms
None
Database Tables
• Refrigerator Types
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 387
Chapter 4. Trying It Out
Function
The Refrigerator Type Menu is a Detail View that lists all the model information about the
particular refrigerator type, and shows a picture if available.
It also has a View all *Model ID* Refrigerators that shows the number of refrigerators in the
region with this particular type. Tapping that button will launch a Lists of Refrigerators
containing all refrigerators in that region of that type.
Implementation
388 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
erators table. The resulting data sets are combined to fill in the display fields on the detail
view.
If the View all *Model ID* Refrigerators button is pressed, odkTables.launchHTML(...) is
called to launch Lists of Refrigerators.
Files
• tables/refrigerator_types/html/refrigerator_types_detail.html
• tables/refrigerator_types/js/refrigerator_types_detail.js
• assets/js/util.js
Forms
None
Database Tables
• Refrigerator Types
• Refrigerators
Administrator Options
Administrator Options are available when the authenticated user is a Table Administrator.
They provide the admin with enhanced permissions, including viewing the entire data set,
creating data visualizations, deleting records, and adding new health facilities.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 389
Chapter 4. Trying It Out
390 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Function
The Administrator Options Menu is the hub that launches the special actions the adminis-
trator can perform. It is only accessible by authenticated Table Administrators. This screen
is accessed by pressing the Administrator Options button the main menu.
The administrator has access the full hierarchy of regions. Above the Administrator Options
button is the list of all the highest tier regions. Tapping any of those individual options will
filter the data into that region. They admin can keep advancing through the regions until
they reach the leaf tiers, which is the same Regions interface.
Implementation
This screen is shown the assets/index.html and /assets/menu.js execute the authenti-
cation code and find a user that is a Table Administrator. This will trigger the function
showSubregionButtonsAndTitle(...) to show the top level regions (see Regions for de-
tails), and the addMenuButton(...) function to add the Administrator Options Button.
When the Administrator Options button is pressed, the function odkTables.launchHTML(.
..) launches assets/coldchaindemo.html. This file defines the four option buttons, and
assets/js/coldchandemo.js handles logic that they trigger.
• View Health Facilities: Launches View Health Facilities with odkTables.
launchHTML(...).
• View Inventory: Launches Inventory with odkTables.launchHTML(...).
• View Refrigerator Models: Launches Refrigerator Types with odkTables.
launchTableToListView(...).
• Add Health Facility: Launches Add Health Facility with odkTables.launchHTML(...).
Files
• assets/index.html
• assets/js/menu.js
• assets/js/util.js
• assets/coldchaindemo.html
• assets/js/coldchaindemo.js
Forms
None
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 391
Chapter 4. Trying It Out
Database Tables
• Health Facility
Function
The administrator can view the full list of health facilities, unfiltered by region. This gives
the administrator full control investigate, modify, or delete any facility in the data set. They
can choose to find a facility with one of two methods:
• Filter By Type:
392 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 393
Chapter 4. Trying It Out
This interface presents a search list that looks and behaves the same
as Lists of Refrigerators. It includes Delete buttons on each entry.
The search box accepts facility ID and facility names.
Implementation
394 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
listQuery value selects all health facilities from the Health Facility table. The
searchParams sets the search fields to facility ID and facility name.
Files
• assets/filterHealthFacilities.html
• assets/js/filterHealthFacilities.js
• assets/filterHealthFacilitiesByType.html
• assets/js/filterHealthFacilitiesByType.js
• tables/health_facility/html/health_facility_list.html
• tables/health_facility/js/health_facility_list.js
• assets/js/list_view_logic.js
• assets/js/util.js
Forms
None
Database Tables
• Health Facility
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 395
Chapter 4. Trying It Out
Inventory
Function
The Inventory option provides two visualizations of the state of the data set, both of which
can be customized to chosen parameters.
• Refrigerator Age
396 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
The refrigerator age visualization presents a bar chart of the current stock
of refrigerators, grouped by age. This can be useful as an assessment of the
quality of the stock and as an estimate of maintenance demands. This graph
can be filtered by region, facility type, and power source. With this option
the administrator might compare the age distribution of refrigerators in the
North and the South regions when allocating upgrade budgets.
• Facility Grid Power Available
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 397
Chapter 4. Trying It Out
The grid power visualization presents a pie chart comparing the ratios of power options
available. This can be filtered by region and facility type.
The data sets to be graphed are filtered with a set of drop menus that can be chosen to
specify the desired data set.
398 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Implementation
The root level HTML file for this option is assets/filterInventory.html. It defines the
two buttons and assets/js/filterInventory.js handles their logic.
Refrigerator Age uses odkTables.launchHTML(...) to launch assets/
filterFrigInventoryForAge.html an assets/js/filterFrigInventoryForAge.js.
The HTML file defines the three drop menus. The values specified by these drop
menus are read and used as query parameter arguments when launching assets/
graphFrigInventoryForAge.html and assets/js/graphFrigInventoryForAge.js. This
JavaScript file uses query parameters provided the caller to construct a SQL query run
an odkData.query(...) call on the Health Facility table. The result of this call are
used to construct a new query that finds refrigerators that match health facilities with an
odkData.arbitraryQuery(...) call on the Refrigerators table. When these results return,
the frigHistogramByAge() function uses that data and the D3 library to render the bar
chart.
Facility Grid Power Available follows the same pattern as Refrigerator Age to present
drop menus and use their values as query parameters. The file that renders this graph
is assets/js/graphFacilityInventoryForGridPower.js. This file also operates similarly
to graphFrigInventoryForAge.js but only performs a single query on the Health Facilities
table. That data set is used, along with D3 by the displayHealthFacilityGridPower()
function to render the pie chart.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 399
Chapter 4. Trying It Out
Files
• assets/filterInventory.html
• assets/js/filterInventory.js
• assets/filterFrigInventoryForAge.html
• assets/js/filterFrigInventoryForAge.js
• assets/filterFacilityInventoryForGridPower.html
• assets/js/filterFacilityInventoryForGridPower.js
• assets/graphFrigInventoryForAge.html
• assets/js/graphFrigInventoryForAge.js
• assets/graphFacilityInventoryForGridPower.html
• assets/js/graphFacilityInventoryForGridPower.js
• assets/js/util.js
Forms
None
Database Tables
• Health Facility
• Refrigerators
400 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.14. Reference Applications
Refrigerator Types
The Refrigerator types list is identical to the interface presented in the Lists of Refrigerator
Types guide. The button is included here as a convenience. See the linked documentation
for details.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 401
Chapter 4. Trying It Out
Function
The Add Health Facility interface provides a method for an administrator to add a new health
facility to the data set. The administrator must specify the region that should contain the
facility (the region must be a leaf tier, it cannot contain other regions). When the Add
Facility button is pressed, a form is launched to fill in the details of the facility.
Implementation
The root level HTML file for this option is assets/addHealthFacility.html. It defines
the button and drop menu and assets/js/addHealthFacility.js handles their logic.
The JavaScript file reads the value from the drop menu and uses it to construct the defaults
argument to odkTables.addRowWithSurvey(...). The variable also includes the group
permissions. The form launched is tables/health_facility/forms/health_facility/
health_facility.xlsx
This form resembles many of the other forms in this application. Mostly select_one prompts
are grouped into screens. The region choices are populated by a query from the queries work-
402 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.15. Deployment Architect Advanced Topics
sheet. The settings, properties, and model worksheets all contain their typical values, setting
the form and table IDs, setting the default view files, and mapping to the database, respec-
tively. The properties file includes security properties including unverifiedUserCanCreate
and defaultAccessOnCreation that restrict which users can use this form.
Files
• assets/addHealthFacility.html
• assets/js/addHealthFacility.js
• assets/js/util.js
• tables/health_facility/forms/health_facility/health_facility.xlsx
Forms
Database Tables
• Health Facility
This section covers advanced topics useful to Deployment Architects. A Deployment Archi-
tect is an author of a data management application or a consumer of collected data. This
person might create forms and edit Javascript on their computer to deploy to the Android
device. Or they might download data from the server and use Excel to perform analysis.
Examples include technical staff and data analytics staff.
Other perspective definitions can be found here.
Limitations
Traditional access control frameworks provide strong protections for data and the manage-
ment of which users can modify that data. The permission filtering introduced in ODK-X is
weaker. When syncing devices with the server, all data rows for all data tables are currently
synced and shared across all devices. Every device gets a full copy of all data. Permission
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 403
Chapter 4. Trying It Out
filtering enables a supervisor to restrict the visibility of that data and to manage who can
modify or delete the data through the programmatic means provided by the ODK-X tools.
This is weaker than traditional access control frameworks in that application designers can:
• Circumvent via software. There are specific ways in which application designers can
write their applications to defeat these filters. When those mechanisms are not em-
ployed, permission filtering provides equivalent policy enforcement to that of a tradi-
tional access control framework.
• Circumvent via external access. The data and attachments are stored as plaintext on
the device. Anyone can copy this data off of the device and access it, or write their
own apps and directly modify it.
It is important to understand these limitations when designing your applications.
Overview
Enforcing restrictions on who can see or modify data requires that the identity of the user
has been verified.
When configuring the Server Settings, any changes to any of the settings (such as the server
URL, type of credential (or anonymous access), username, password or Gmail account)
will clear any prior user identity and capability information and flag the user identity as
unverified.
When leaving the Server Settings screen, a user-verification screen will then be presented
(unless no server sign-on credential is specified, in which case anonymous access to the server
will be attempted):
404 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.15. Deployment Architect Advanced Topics
Clicking the Verify User Permissions button on this screen will initiate a series of requests to
the configured server. These requests verify that the server URL is correct, that the server
works with this application name, and then verify the server sign-on credential that has been
configured on the Server Settings page.
Warning: If the server sign-on credential is rejected, the user identity will be flagged
as unverified and any further interactions on the device will be performed as if by an
anonymous user.
As part of the user-verification process, once the user’s identity has been verified, the list
of groups to which this user belongs and the capabilities (roles) assigned to that user are
downloaded from the server. These are cached on the device for use during data access
filtering until the user logs out of the ODK-X tools on the device or a different server sign-on
credential is specified.
For the purposes of the data access filtering mechanism, there are 4 user capabilities of
interest:
• ROLE_USER – a user who is able to verify their identity.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 405
Chapter 4. Trying It Out
Management of which unprivileged users can see, modify or manage access to a given row is
controlled through five access filter columns. The first of these columns specifies the access
to the row that is granted to all unprivileged users. The second identifies the owner of this
row. Row owners have modify privileges on a row. The other three are either null or specify
a user group that is granted that specific access right:
• _DEFAULT_ACCESS – one of HIDDEN, READ_ONLY, MODIFY or FULL.
• _ROW_OWNER – this user has FULL privileges on this row.
• _GROUP_READ_ONLY – a user who is a member of this group will be able to
read this row of data
• _GROUP_MODIFY – a user who is a member of this group will be able to read
and modify this row of data but not delete it.
• _GROUP_PRIVILEGED – a user who is a member of this group will be able to
read, modify, delete and change privileges on this row of data.
Note: Privileged users are not governed by these settings – they have unlimited access to
all tables on the device.
Individual users can belong to any number of groups, enabling arbitrarily complex row-level
access management. Users may also be assigned a default group. Management of group
406 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.15. Deployment Architect Advanced Topics
memberships is dictated by the server being used. Refer to the ODK Cloud Endpoints
for the capabilities of the different servers. More detail will be given regarding these filter
columns in the Row-level Access Filters section.
Inside ODK Survey and ODK Tables web pages, the groups and roles of the current verified
user are available in JavaScript via the API:
odkData.getRoles(function(result) {
var roles = result.getRoles();
// roles is an array of capabilities granted to the verified user.
// It will be null for anonymous and unverified users.
}, function(errorMsg) {
// error handler
});
Inside ODK Survey and ODK Tables web pages, the default group of the current verified
user is available in JavaScript via the API:
odkData.getDefaultGroup(function(result) {
var defaultGroup = result.getDefaultGroup();
// defaultGroup is null or a string
}, function(errorMsg) {
// error handler
});
Note: Default groups are not directly used within the ODK-X framework. These are
provided for use by an application designer when crafting their application.
Whenever the server is contacted to verify a user’s identity, if the user is determined to be
a privileged user, the server will, additionally, provide a list of all users configured on the
server and all of the groups and roles assigned to those users. This list can be useful when
performing task assignments via assigning row ownership.
This list will contain entries of the form:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 407
Chapter 4. Trying It Out
{
user_id: "verified_identity_token",
full_name: "content of the Full Name field on the server",
default_group: "default group of the user"
roles: [...]
}
The Full Name field on the server (on the Site Admin → Permissions sub-tab) is provided
here to allow super-users and administrators to select people by name. user_id should be
stored in the _ROW_OWNER column to assign ownership to this user. The list of roles
(and groups) is provided to allow super-users and administrators to choose users based upon
their capabilities.
If the user has been assigned to a default group it will be provided. Default groups are not
directly used within the ODK-X framework. These are provided for use by an application
designer when crafting their application.
Inside ODK Survey and ODK Tables web pages, the list of all configured users is available
in JavaScript via the API:
odkData.getUsers(function(result) {
var users= result.getUsers();
// users is an array of the above objects.
// It will be null for anonymous and unverified users.
// It will be a singleton list if the user lacks permissions.
}, function(errorMsg) {
// error handler
});
408 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.15. Deployment Architect Advanced Topics
These three table properties can be specified in the properties sheet of the XLSX file. If they
are not specified, the default values for these three properties are:
Control of who can see, modify, or delete an individual row is governed by the row-level
access filter columns of that row and that row’s sync status. As described earlier in this
page, these filters are stored in the row itself under the _default_access, _row_owner,
_group_read_only, _group_modify, and _group_privileged metadata columns. The sync
status of the row is also stored in the row itself under the _sync_state metadata column.
Row-level access will always be one of:
• Not visible
• r – Read-only access to the row
• rw – Read and modify access to the row. Deletion is not allowed. Modification of the
row-level access filter columns is not allowed.
• rwd – Read, modify and delete access to the row. Modification of the row-level access
filter columns is not allowed.
• rwdp – Read, modify and delete access, plus the ability to modify the row-level access
filter columns.
The rules for the row-level access filter are as follows (stop at the first rule that applies):
1. Super-users and administrators have full read/write/delete(rwd) capabilities
on all rows, regardless of their row-level access filters and independent of the
table’s locked status. These privileged users also have the ability to change
the row-level access filter column values (ordinary users cannot).
2. If a row has not yet been synced to the server, the current user has full
read/write/delete (rwd) capabilities on that row. This includes the anony-
mous and unverified users and is independent of the table’s locked status.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 409
Chapter 4. Trying It Out
3. If the _row_owner column contain the user_id of the current user, then this
user has full read/write/delete (rwd) capability on this row or, for locked
tables, can modify the row (but cannot delete it).
Note: _row_owner can be null or any arbitrary placeholder string. If you use placeholder
strings, it is recommended that they not begin with username: or mailto: or be anonymous
to prevent any possible collisions with existing usernames. Placeholder strings might be
useful in workflows to designate queues of unassigned-work.
Super-users and administrators can update the row-level access filters via the JavaScript
API:
410 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.15. Deployment Architect Advanced Topics
// error handler
});
Alternatively, super-users and administrators can also use the updateRow API.
Ordinary users will receive a not-authorized error if they attempt to set any of these metadata
fields (even if the values they set are unchanged from the current values of those fields).
When a SQL query is processed inside the ODK Services layer, it is first examined to
see if the result set contains the columns _sync_state, _default_access, _row_owner,
_group_read_only, _group_modify, and _group_privileged. If it contains all six columns,
then the query is wrapped with a where clause to exclude hidden rows and that, in turn, is
wrapped by whatever limit and offset you have specified for the query.
Warning: If you issue a query that omits one or more of these six columns from the
result set, then no HIDDEN filtering will be applied. This is one way to circumvent data
permission filtering in software – by crafting queries that omit one or more of these fields.
For example, queries that return the maximum value in a field:
SELECT MAX(crop_height) as max_height FROM crop_plantings
Would return the maximum crop height across all crop planting – even if the current user
only had access to the crop height data for their own plantings (and the crop information
from other farms was hidden from them).
If you want to restrict such calculations to just the data visible to the current user, you
must manually construct the query to do so. This would be the revised query:
SELECT MAX(crop_height) as max_height FROM crop_plantings WHERE _default_
,→access != ? or _row_owner = ? bind parameters = [ "HIDDEN", odkCommon.
,→getActiveUser() ]
Effective Access
As mentioned above, when a SQL query is processed inside the ODK Services layer, it is
first examined to see if the result set contains the columns _sync_state, _default_access,
_row_owner, _group_read_only, _group_modify, and _group_privileged. If it contains
all six columns, then a synthesized column, _effective_access is added to the result set.
That column returns one of r, rw, rwd, or rwdp (with the p indicating that a user can change
permissions for the row as well) to indicate the level of access the current user has on the
rows in the result set.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 411
Chapter 4. Trying It Out
Additionally, once a result set is returned for a given table, you can determine whether the
current user can create new rows on the table by calling getCanCreateRow
Consider a workflow application where a first group of field agents create work requests, those
requests are then sent to a supervisor who assigns them to a different set of field agents for
processing.
In this case, you might configure a work_requests table to create rows with a HIDDEN
default access (via defaultAccessOnCreation). Then create a form for opening work re-
quests.
The first group of agents (ordinary users) uses that form to create new work requests. Each
agent would only see the work requests they themselves create because all other rows in that
table would be hidden due to the _default_access being HIDDEN and due to their being
ordinary users.
After the field worker in the first group syncs to the server, and the supervisors sync to the
server, the set of work requests the field worker created will have become available on the
supervisors’ devices. The supervisor (a super-user or administrator) can then see and change
the _row_owner on each work request to one of the field agents in the second group.
When the supervisor syncs to the server, and then the field agent in the second group
(another ordinary user) syncs to the server, that field agent will see the work items that
have been assigned to them (and they will not see any other work items because they are
ordinary users of the system).
When the agent in the first group next syncs, their created work item will disappear from
their view because it is HIDDEN and the _row_owner no longer matches this field agent’s
verified user id (it was assigned to the second agent).
412 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.15. Deployment Architect Advanced Topics
Upon completion of the task and after syncing to the server, after the supervisor next syncs,
the supervisor could then change the _row_owner to null or to a special placeholder value
to remove it from the second agent’s list of work items (and that removal would occur when
that second agent next syncs with the server after the supervisor syncs his _row_owner
change).
Example Application
The app designer has a row-level access demo using the geoweather and ge-
oweather_conditions tables and forms.
$ grunt adbpush-tables-rowlevelaccessdemo
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 413
Chapter 4. Trying It Out
enforced.
Change your Server Settings to different users to see how their effective accesses change.
4.15.2 Internationalization
Internationalization of web page content is achieved through the API exposed in the od-
kCommon object and the configuration contained in the XLSX files for the framework form
and for the forms with formIds that match their tableIds:
/opendatakit/{appName}/config
/assets/framework/forms/framework/framework.xlsx
/tables/{tableId}/forms/{tableId}/{tableId}.xlsx
Within the framework XLSX file, the framework_translations sheet defines the translations
for all of the Survey form labels and prompts. On this page, the string_token column
contains the identifier for a particular label or prompt translation. The text.default column
provides the default translation for that label or prompt, and all subsequent text.{langCode}
columns provide translations for each of those specific language codes (e.g., {langCode} might
be es for Spanish). If the label or prompt supports image or media enhancements, there will
also be image.default and image.{langCode} or audio… or video… columns providing differing
content for those.
Also within the framework XLSX file, there can be an optional common_translations sheet
following the same format as the framework_translations sheet. This can be used to provide
an application-wide set of translations.
Similarly, within the tableId.xlsx file, there can be an optional table_specific_translations
sheet that also follows the same format as the framework_translations sheet. This is used
to provide a table-specific set of translations.
The list of {appName}-wide locales and the default locale are specified on the framework
form’s settings sheet. Individual Survey forms may define additional translations, but those
414 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.15. Deployment Architect Advanced Topics
In order to access translations, your web page must load the commonDefinitions.js file and
the tableSpecificDefinitions.js files. Within Tables web pages, you can then obtain
the appropriate translation via:
Additional methods are available within odkCommon to test whether a translation exists,
and to obtain a localized image, audio or video URL. Refer to that file for the available
methods.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 415
Chapter 4. Trying It Out
And finally, to access the list of locales, you can directly access that via:
window.odkCommonDefinitions._locales.value
This is an array of objects (no particular order). Each object has a display.locale entry that
can be translated to the current display language, and a name which is the {langCode} for
that locale.
And the default locale is available at:
window.odkCommonDefinitions._default_locale.value
After defining your translations on the framework and tableId XLSX files, the XLSXCon-
verter must be run on these files to generate the translation files.
When the XLSXConverter processes the framework.xlsx file and emits two files (in addition
to the formDef.json):
/opendatakit/{appName}/config
/assets/commonDefinitions.js
/assets/framework/frameworkDefinitions.js
/opendatakit/{appName}/config
/tables/{tableId}/definition.csv -- data definition
/tables/{tableId}/properties.csv -- table properties
/tables/{tableId}/tableSpecificDefinitions.js
416 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.15. Deployment Architect Advanced Topics
/opendatakit/{appName}
/config
/assets -- common shared configuration
app.properties -- application properties
index.html -- HTML home page for Tables (if configured)
/css -- common css files
/fonts -- common font files
/img -- common image files
/js -- common javascript files written by you
/libs -- common 3rd party javascript libraries
... additional directories and files
...
tables.init -- identifies what to process during initialization
/csv/{tableId}[.{qualifier}].csv
/csv/{tableId}/instances/{cleanrowId}/{row-level-attachment-files}
...
/commonDefinitions.js -- shared translations (available in all␣
,→webkits)
/tables
/{tableId}/definition.csv -- defines the data model of the table
/{tableId}/properties.csv -- properties of the tableId
/{tableId}/forms/{formId}/{formId}.xlsx -- XLSX form
/{tableId}/forms/{formId}/formDef.json -- created from XLSX
... optional additional form definition files
/{tableId}/forms/{formId}/customTheme.css
/{tableId}/forms/{formId}/customStyles.css
/{tableId}/forms/{formId}/customPromptTypes.js
/{tableId}/forms/{formId}/customScreeenTypes.js
/{tableId}/forms/{formId}/{other-files}
... end optional additional form definition files
/{tableId}/html/{optional-html-files}.html
/{tableId}/js/{optional-js-files}.js
... any other directories and files you might want
...
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 417
Chapter 4. Trying It Out
418 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
the validate operation and resume the validation check after the user corrects the first
invalid field value). Then traverse all fields with the indicated sweep_name and verify
their compliance. Upon finding a field that fails validation, retrieve the begin_screen
operation that contains that prompt, set that operation as the new current operation
and mark it as ’popHistoryOnExit’. If all fields validate successfully, pop the section
history stack (removing the ’validateInProgress’ entry) and execute advance.
• resume – pop the history stack (unwind to the previous rendered screen) and render
that screen. If popping the history stack would have exited the section, exit the section
and advance to the next screen after the ’do_section’ command.
• save_and_terminate – save all changes and close the WebKit.
This section covers advanced topics useful to Platform Developers. A Platform Developer is
a programmer that intends to modify the source code of the ODK-X tools themselves. This
person might want to add a new view type or a fix a bug.
Other perspective definitions can be found here.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 419
Chapter 4. Trying It Out
– Controller
– ScreenManager
– Screen
– Prompt
– Survey Controller Actions
The XLSXConverter converts the XLSX file defining an Survey form into a JSON repre-
sentation of that form. This representation is then layered on top of the generic Survey
JavaScript framework to produce the JavaScript code that is executed when filling out the
form.
The primary building blocks of this generic Survey JavaScript framework are:
• bootstrap - for prompt UI and behavior
• Handlebars - for HTML content rendering
• Backbone - for event handling within prompts
• requirejs - for module dependencies and loading
• jQuery - generic utility functions
• underscore - generic utility functions
• moment - date and time handling support
Some additional libraries are use for specific widgets and capabilities (for example, d3 for
graphing, combodate for calendar widgets).
The Survey JavaScript framework then adds form navigation, data validation, data storage
and data retrieval functions. Central to this framework is the calling context which pro-
vides a continuation abstraction for chaining and resuming processing during asynchronous
interactions.
420 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
– Database
* Retrieving Information About a Database Table
* Creating and Deleting a Database Row
* Getting and Modifying Fields In a Database Row
* Utility Functions for Parsing Selection and Order-By Clauses
– Controller
– ScreenManager
– Screen
– Prompt
– Survey Controller Actions
The success and failure callbacks used within the odkData API are also used throughout the
Survey JavaScript. These are so common, that they are passed into functions as a single
”calling context” argument, generally named ctxt. Whereas many libraries have success and
failure callbacks:
• obj.action(successCallbackFn, failureCallbackFn);
the Survey JavaScript would just pass in the ctxt object:
• obj.action(ctxt);
This ctxt object consists, at a minimum, of a success function and a failure function. The
failure function generally takes one argument which is an object containing a message field
that holds an error message. The success function may pass in an argument or not.
These calling contexts are created, tracked and managed by the controller class via:
• window.controller.newContext( event ) – when needed during event processing
• window.controller.newCallbackContext() – on callbacks from Java shim
• window.controller.newStartContext() – special case
• window.controller.newFatalContext() – special case
The ctxt object extends the baseContext defined within controller, which has:
{
contextChain: [],
append: function( method, detail ) {...},
success: function() {...},
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 421
Chapter 4. Trying It Out
A well-written success() or failure(msg) function will perform its actions then call the
success or failure function of the parent instance from which it is extended. So you will often
see code like this in Survey JavaScript:
Where postRender(ctxt) will be responsible for calling the success or failure methods of
the ctxt object that was extended and passed into the render() method. The failure(msg)
code, in contrast, just logs a message to the context log (via append(), discussed below), and
calls the parent instance’s failure function.
By always calling the parent instance’s success or failure function, you can do interesting
things, like implement mutexes (an advanced software construct) – because you are always
assured that if you extend a ctxt, that one of your failure(msg) and success() functions will
always be called.
The failure(msg) function takes an argument, which is an object that may contain an optional
‘message’ parameter, which could be a description of what the failure was. This is used during
validation.
The use of the ctxt object enables you to store values within the ctxt, and ensure that these
are available later in your code, or, via extending it, to change the success function so that it
takes an argument, etc., as needed by your code (the database layer quite frequently needs
to pass values into the ctxt success method).
The append() function on the context enables you to append a log record to the context.
The baseContext’s success() and failure(msg) methods both cause the accumulated log mes-
sages to be written via the odkCommon.log(). On Chrome, the log message is suppressed.
On Android, it is written to the /opendatakit/appName/output/logging directory and
emitted in the system log if an error or warning.
The ‘seq:’ and ‘seqAtEnd:’ values emitted in these logs are useful for understanding what
events are processed concurrently within the JavaScript. ‘seq’ is the sequence number of this
context, and ‘seqAtEnd’ is the sequence number of the newest context in-process at the time
this context completes.
Note that when interacting with other asynchronous frameworks, it is easy to convert from
ctxt-based style to the success/failure function style:
422 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
Finally, these calling contexts are very similar to JavaScript promises. However, within the
Survey JavaScript, the typical construction is to insert processing steps before taking the
success or failure action of the incoming calling context. In contrast, with promises, the
typical construction is to append processing steps upon completion of the promise.
In the rare cases when it is necessary to append actions after a calling context chain completes
(like the Promise model), two APIs are provided:
• ctxt.setChainedContext(aCtxt);
• ctxt.setTerminalContext(aCtxt);
Chained contexts are executed in-order, depth-first, from first registered to last registered,
after which all terminal contexts are executed in the order in which they were collected from
within all of the executed chained contexts. In practice, the Survey JavaScript framework
only makes use of terminal contexts, and those usages only register a single terminal context.
All user forms processed within Survey load the same HTML file. Form-specific content
and behaviors are specified via the window.location.hash portion of the URL. The common
HTML file is here:
/opendatakit/{appName}/system/index.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenDataKit Common Javascript Framework</title>
<link rel="stylesheet" type="text/css" id="custom-styles" />
<link rel="stylesheet" type="text/css" id="theme" href="libs/bootstrap-3.3.7-
,→ dist/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="../config/assets/css/odk-survey.
,→css" />
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 423
Chapter 4. Trying It Out
</head>
<body>
<div id="block-ui"></div>
<div class="odk-page">
<div class="odk-screen">
<div class="odk-toolbar"></div>
<div class="odk-scroll">
<div class="odk-container">Please wait...</div>
</div>
<div class="odk-footer"></div>
</div>
</div>
<script type="text/javascript" data-main="survey/js/main" src="libs/require.
,→2.3.3.js"></script>
</body>
</html>
This loads a /config/assets/css/odk-survey.css file that users can customize, loads the
common JavaScript wrapper objects and translation files, and finally triggers requirejs to
load the framework and (eventually) process the window.location.hash to load and interpret
the form definition.
The requirejs module management framework, under the direction of the /system/survey/
js/main.js configuration and initialization file, loads the JavaScript files used by the Survey
form framework.
Listed alphabetically, these are:
• builder - responsible for reading the formDef.json and initializing the controller with
the list of prompts in the survey.
• controller - handles the logic for moving from one prompt to the next; this includes
pre- and post- actions and performing the validation logic.
• database - Handles the interactions with the odkData interface to the database. This
also constructs and maintains the in-memory model description holding the form def-
inition and the instance’s data and of the structure of the table in which it is stored.
• databaseUtils - contains utility functions for transforming between the database stor-
age strings and the JavaScript reconstructions in the model.
424 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 425
Chapter 4. Trying It Out
Main
The main.js file declares the interdependencies among the various JavaScript frameworks.
It relies on requirejs for package dependency management and loading. The code first loads
jQuery and an extended regex library (for Unicode strings). Once those are loaded, it then
loads additional 3rd party libraries and the main Survey JavaScript framework files via:
Once the ODK frameworks has loaded, the body of the function is executed. The body then
initializes the parsequery object (needed to avoid circular references):
parsequery.initialize(controller,builder);
And then either triggers a reload to clean up the window.location value or initiates the
parsing of the formDef.json specified in the URL location.hash via:
426 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
parsequery.changeUrlHash(ctxt);
Parsequery
parses the formDef and calls the controller to initiate the processing of data callbacks from
the Java layer.
The second entry point is _prepAndSwitchUI, which is called deep within the processing
performed inside changeUrlHash(ctxt) and also by the controller when opening a specific
instanceId within a form. That entry point assumes that the tableId and formId have not
changed from what they currently are.
parsequery._parseParameters(ctxt) has the following flow (accomplished with many
asynchronous processing steps – arguments are omitted):
parsequery._parseParameters() {
if ( !sameForm ) {
controller.reset( function() {
// webpage now displays "Please wait..." with translations
parseQuery._parseFormDefFile();
});
} else {
parseQuery._parseQueryParameterContinuation();
}
}
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 427
Chapter 4. Trying It Out
From this flow, you can see that the rough sequence of flow is:
428 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
Builder
Builder’s only entry point is buildSurvey. This attempts to load several well-known files and
then processes the formDef.json.
It begins by attempting to load (in order):
/opendatakit/{appName}
/config/tables/{tableId}/tableSpecificDefinitions.js
/config/tables/{tableId}/forms/{formId}/customScreenTypes.js
/config/tables/{tableId}/forms/{formId}/customPromptTypes.js
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 429
Chapter 4. Trying It Out
• formula(arg1[, arg2[,…]])
• requirejs_path
Columns with the function type are expected to contain column values ({columnValue}) that
are a text string that can be evaluated as a function definition – for example, {columnValue}
would be something like: function() { return 3; }.
The formula type and the formula(...) type are expected to have {columnValue} be an
expression that is the return value of a function. These are wrapped by the builder to
construct either
or
Function and formula column types have their content evaluated in the context of the meth-
ods exposed by formulaFunctions to produce JavaScript functions. Because they are evalu-
ated within the formulaFunctions context, they only have limited access to the internals of
the Survey framework. This intentionally limits their power and the potential for damage
that they might otherwise wreak.
The requirejs_path type causes builder to prefix the path to the form’s directory. This
supports referencing custom prompt templates and, potentially, images and other media,
that are stored in the form directory.
The default column_types map can be extended in the XLSX file by defining a column_types
sheet with headings that are column names and a single row beneath that defines the column
type for that column name.
The default column_types map consists of:
{
_screen_block: 'function',
condition: 'formula',
constraint: 'formula',
required: 'formula',
calculation: 'formula', // 'assign' prompt and on calculates sheet.
newRowInitialElementKeyToValueMap: 'formula',
openRowInitialElementKeyToValueMap: 'formula',
selectionArgs: 'formula',
url: 'formula', // external_link prompt
uri: 'formula', // queries
callback: 'formula(context)', // queries
choice_filter: 'formula(choice_item)', // expects "choice_item" context arg.
templatePath: 'requirejs_path'
}
430 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
Builder uses the column_types field in the specification object within the formDef.json to
convert fields (column names) into their appropriate types. This conversion consists of a
a full traversal of content from the calculates, settings, choices, queries, and all the survey
sheets in the original XLSX file.
Next, for each of the survey sheets, builder creates Backbone instances of the prompt types
referenced on those sheets, one instance for each declared prompt. These instances fold the
field definitions the user specified in the XLSX file on top of the default values provided by
the prompt definitions (and custom prompt definitions), allowing the user to customize the
prompt through explicit changes in the XLSX file. These prompt instances are used when
rendering the survey.
Lastly, the builder attempts to load:
/opendatakit/{appName}
/config/tables/{tableId}/forms/{formId}/customStyles.css
/opendatakit/{appName}
/config/tables/{tableId}/forms/{formId}/customTheme.css
Or, if that doesn’t exist, it examines the formDef.json to see if there was a theme defined on
the settings sheet of the XLSX file and attempts to load:
/opendatakit/{appName}
/config/assets/css/{theme}.css
And, lastly, it examines the formDef.json to see if there was a font-size defined on the settings
sheet of the XLSX file and attempts to set it in the body:
$('body').css("font-size", fontSize.value);
Database
The Survey database layer is a fairly thin wrapper around the odkData object. It maintains
a cache of all of the field values in the referenced instanceId (row) within the current form.
This cache is synchronously referenced and modified within the presentation layer and asyn-
chronously updated via calls to the odkData object. In general, these asynchronous writes
occur during lose-focus event processing.
Additionally, it maintains a copy of the properties of that table (for example, display name
of the table and display names of the fields) and a description of the field types in the
database table (the table definition). These are returned via the odkData object. This
information is used within Survey to enable formulas to refer to field values either via their
elementPath or via the database column in which they are stored (elementKey). A prime
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 431
Chapter 4. Trying It Out
example of this is a geopoint. If the name of the geopoint field is mylocation then the
individual latitude, longitude, etc. values are maintained within the cache as individual
keys within a mylocation object – you can refer to them naturally as mylocation.latitude,
mylocation.longitude, etc. This is the elementPath representation of these fields. However,
within the database layer, these are stored as individual columns with column names of
mylocation_latitude, mylocation_longitude etc. That is the elementKey representation. A
similar transformation occurs for file attachments and any user-defined complex data type
(multi-valued prompts). Simple select-multiple prompts, which manipulate arrays of values,
have an elementPath representation within the cache as a Javascript array of selected values.
Within the database layer, their elementKey representation is a JSON serialization of this
array (in contrast, select-multiple prompts that reference linked tables would not store their
selections in the dominant data table but rely upon filter conditions and storing a (foreign)
key in the subordinate table, or in an association table, to establish their linkage).
The support this synchronous cache and this data abstraction, the main entry points for this
layer can be divided into 4 sections:
1. Retrieving Information About a Database Table
2. Creating and Deleting a Database Row
3. Getting and Modifying Fields In a Database Row
4. Utility Functions for Parsing Selection and Order-By Clauses
Two methods:
• initializeTables(ctxt, formDef, tableId, formPath)
• readTableDefinition(ctxt, formDef, tableId, formPath)
The first is called during the initial loading of the form; the second is used by linked table
prompts.
Five methods:
• initializeInstance(ctxt, model, formId, instanceId, sameInstance,
keyValueMap)
• get_linked_instances(ctxt, dbTableName, selection, selectionArgs,
displayElementName, orderBy)
• save_all_changes(ctxt, model, formId, instanceId, asComplete)
• ignore_all_changes(ctxt, model, formId, instanceId)
432 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
Five methods:
• setValueDeferredChange( name, value )
• getDataValue(name)
• getInstanceMetaDataValue(name)
• applyDeferredChanges(ctxt)
• setInstanceMetaData(ctxt, name, value)
The first 3 of these methods are the standard setters and getters of values. In general, the
metadata fields of a row are read-only within Survey JavaScript. For this reason, there is no
synchronous setter method for these fields.
The last 2 methods, applyDeferredChanges and setInstanceMetaData, are used internally
within the Survey JavaScript framework to flush the changes in the synchronous cache
through to the database via calls to odkData. Nearly all manipulation of a row’s instance
metadata is done within the Java layer. The exception is the changing of the current row’s
locale, which is effected via the call to setInstanceMetaData.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 433
Chapter 4. Trying It Out
Two methods:
• convertSelectionString(linkedModel, selection)
• convertOrderByString(linkedModel, order_by)
These functions examine where clauses and order-by clauses to replace any elementPath
expressions with elementKey values. Because this is not within the database layer, these
conversions are not entirely fool-proof.
Controller
controller.startAtScreenPath(ctxt, screenPath) {
var op = operation corresponding to screenPath.
controller._doActionAt(op);
}
//
// starting at the operation referenced by 'op',
434 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 435
Chapter 4. Trying It Out
}, 500);
screenManager.setScreen(ctxt, screenOp, options);
}
Simply put, the processing flow eventually calls screenManager to display a screen (via
setScreen(ctxt, screenOp, options)) and perhaps also shows a pop-up with some sort of alert
or error message (via showScreenPopup(m)).
When the next button is pressed or the screen is swiped forwards, the framework calls
controller.gotoNextScreen() which verifies that all required fields are filled-in and all
constraints are applied. It then triggers much the same processing sequence – calling doAc-
tionAt() with the operation after the currently-rendered screen.
When the back button is pressed or the screen is swiped backward, the framework calls
controller.gotoPreviousScreen() which pops the operation history stack for the current
survey sheet until a screen-rendering operation is found, and that screen is then rendered.
And, if the history for the current survey sheet is exhausted, then the contents screen for
that sheet is displayed.
Finally, returning to the discussion of the control flow on the initial load
of a form, after the current screen is rendered, the call to controller.
registerQueuedActionAvailableListener() causes an action listener to be registered
with odkCommon and then calls that listener to process any results that became available
before the listener was registered. If there are any results from a previous odkCommon.
doAction(...intentArgs...) request (for example, a media-file capture request), then the
controller’s action listener will interpret the results to identify what prompt in the current
screen should receive and process these results and then invoke that prompt to complete
the processing. Otherwise, if there are no results, no additional actions are taken. This
completes the control flow on the initial load of the form.
ScreenManager
The screenManager provides event handling for swiping and the navigation bars at the top
and bottom of a screen. It delegates to the screen object to construct the DOM represen-
tation for that content and also delegates to the screen object to register and unregister
event handlers for any other DOM elements via calls to recursiveUndelegateEvents()
and recursiveDelegateEvents(). Those event handlers are expected to be defined in the
Backbone-based screen objects and prompt objects.
The high-level actions of the screen manager are:
screenManager.setScreen(ctxt, screen) {
// show "loading..." spinner
screenManager.showSpinnerOverlay();
// stop processing all events on the current screen
screenManager.disableSwipeNavigation();
436 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
screenManager.activeScreen.recursiveUndelegateEvents();
// construct the DOM objects in the page (heavily nested)
screen.buildRenderContext(... {
screen.render(... {
screenManager.activeScreen = screen;
// replace the screen
screenManager.$el.find(".odk-page").replaceWith(screen.$el);
});
});
//
// and via a ctxt.terminalContext() registration
// so that the DOM replacement and redraw can take effect
screenManager.activeScreen.afterRender();
screenManager.activeScreen.recursiveDelegateEvents();
screenManager.hideSpinnerOverlay();
}
Screen
The screen object determines the set of prompts that should be displayed and lays them
out. The custom screen example shows how this can be done within an arbitrary HTML
template by using ids on DOM elements to identify where the inner HTML for a prompt
should be injected.
Immediately prior to screen rendering, any unsaved changes in data values are asyn-
chronously flushed to the database.
The screen object also enforces required fields and constraints and can reject any attempts
by the controller object to move off of this screen or pop-up a confirmation for the user to
accept.
See the screens.js file.
Prompt
Prompts register event handlers for their DOM elements and are responsible for restoring
and saving values displayed in those DOM elements into the synchronous data cache and for
validating those values and enforcing any constraints (if so directed).
See the prompts.js file.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 437
Chapter 4. Trying It Out
As mentioned earlier, the main processing loop within the controller executes a program
derived from the form’s XLSX file and encoded in the formDef.json. The 10 primitive
operations in this program are described in ODK Survey Controller Actions.
• xlsx Component
• specification Component
• sections Sub-Component
• operations Sub-Sub-Element
– assign
– begin_screen
– goto_label
– do_section
– exit_section
– back_in_history
– advance
– validate
– resume
– save_and_terminate
The XSLSXConverter in the AppDesigner reads the XLSX form definition file and produces
a set of output files, including formDef.json, as described earlier in this document.
In general, users of Survey will not directly interact with this file. Instead, they would write
their forms in the XLSX file. Several features of Survey support that simplified usage:
1. custom screens and prompts can be defined in separate JavaScript files (see the earlier
discussion of the Builder processing sequence). These custom prompts and screens can
then be referenced by name in your XLSX form definition. This allows new widgets to
be defined without extending the XLSX syntax or the XLSXConverter.
2. if additional member variables or functions are needed in your prompt logic, you can
define these simply by adding a column with that member variable name to the survey
sheet. If there is a value in that field, the member variable will be created and present
438 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
in the prompt instance when the form is being rendered. Use the column_types sheet
to define the interpretation of these members (e.g., to interpret them as functions or
formulas). Member variables that are objects can be created by using ’.’ to separate the
member variable name from the field name, as is done with the display.* columns, which
define a member variable that is an object with various fields (e.g., display.prompt,
display.text, etc.). Array-valued member variables can be created using [0], [1], etc. to
specify the values in the array.
3. custom CSS styles and themes can be defined. Additionally, the full power of JavaScript
is available when needed.
A primary goal of the formDef.json format was to preserve enough of the original source
document (XLSX) to enable that document to be roughly reconstructed. The cell locations
and values of all the cells in the XLSX file are retained, but formatting and coloring of the
cells is not preserved. One can theoretically write an inversion program that would take this
information and reconstruct an XLSX file without formatting or cell coloring that would
be functionally equivalent to the original source XLSX file. This solves a common issue in
the JavaScript-based tools where the conversion process fails to preserve enough information
about the source document to enable it to be recreated.
Additionally, while the XLSXConverter performs numerous cross-checks, some errors cannot
be reported until the form is executed. When these occur, error messages must identify the
sheet, row and column in which the error occurred so that it is easy for form designers to
correct the issues.
With this understanding, the structure of the formDef.json file consists, at the top level,
of an object with 2 fields:
{
xlsx: {...},
specification: {...}
}
xlsx Component
Note that alternative form description environments, such as drag-and-drop form builders,
are expected to produce content that might be stored under a different field name. As those
other tools develop, it is expected that some error message handling will need to be revised
to properly report errors against those other source descriptions.
The purpose of this component is to enable an inversion tool to generate an XLSX file that
is functionally equivalent to the source XLSX that generated this formDef.json.
Note: Writing custom prompts that directly reference the content of the xlsx component
is fragile and should be discouraged. Future versions of the Survey JavaScript framework
may delete this component from the formDef.json structure that is retained during form
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 439
Chapter 4. Trying It Out
execution. Remember that prompts will automatically possess member values and functions
that you have defined on the survey sheets, so there is little need to retrieve information by
directly access the formDef.json structure.
The xlsx object has field names that correspond to the names of the sheets in the originating
XLSX file. Each sheet in the XLSX file is assumed to have a header row followed by data
rows beneath it. The values for these sheet-name fields are arrays of objects, one or each
data-row on that sheet. i.e., the header row is omitted. Each of these row objects will contain
a _row_num field with the corresponding row number in the original XLSX file.
If a cell in the originating XLSX file’s data-row was not empty, the corresponding data-row
object will have a field with the column name from the header-row and this value as the
field-value. For complex header-row column names, like display.prompt.text, the resulting
data-row object will have a display field with an object value with a prompt field with an
object value with a text field with the cell content. In cases where a value for the root cell:
display.prompt.text and a cell field: display.prompt.text.en are both specified, the value in
the root cell (display.prompt.text) will be pushed down into a default field.
Here is a portion of the xlsx structure showing the content of the first data row of the survey
sheet from the example form:
"xlsx": {
"survey": [
{
"type": "integer",
"name": "default_rating",
"display": {
"prompt": "first_prompt",
"hint": {
"text": "If the form does not yet have a rating, this will be␣
,→proposed for the rating value. This value is not retained in the survey result␣
,→set and exists only for the duration of this survey session."
}
},
"model": {
"isSessionVariable": true
},
"_row_num": 2
},
...
Note: Recreating the XLSX file from this structure is mechanical but the reconstruction
cannot preserve the order of the header columns, since that information has already been
discarded.
440 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
specification Component
The specification component of the formDef.json object is the only part of that is active
used by the Survey JavaScript framework. This component contains the following fields:
• column_types – used by builder. Can be extended by adding a column_types sheet
in the XLSX file.
• settings – content from the settings sheet in the XLSX file. This is an object with
field names corresponding to the setting_name on that sheet with values correspond-
ing to the data-row matching that setting name. Retrieve a given setting_name
via a call to opendatakit.getSettingObject(opendatakit.getCurrentFormDef(),
setting_name) There are accessor methods defined in the opendatakit.js JavaScript
file for retrieving common settings values.
• choices – content from the choices sheet in the XLSX file. This is an object with
field names corresponding to the choice_list_name on that sheet. The values for these
fields are arrays of objects, one object per row matching that choice_list_name in
the order in which they appear in the choices sheet. This information is returned
as part of all data row fetches and queries and is accessible on the odkData re-
sult object via calls to resultObj.getColumnChoicesList(elementPath) and, for
individual data values, you can access the object corresponding to that data value
most efficiently via resultObj.getColumnChoiceDataValueObject(elementPath,
choiceDataValue). Within Survey, the prompts use a wrapper function:
opendatakit.getChoicesDefinition(choice_list_name) to access the choices list.
The choices field should eventually be removed as the above calls on the result object
are definitive and those choice lists come from the choices sheet of the form whose
formId matches the tableId. The choices sheet within each form XLSX file will be
retained until the AppDesigner and XLSXConverter can become smarter.
• queries – content from the queries sheet in the XLSX file. This is an object with field
names corresponding to each query_name on that sheet. The values for these fields are
objects corresponding to the data-row matching that setting name. Retrieve a given
query_name via a call to opendatakit.getQueriesDefinition(query_name)
• calculates – content from the calculates sheet in the XLSX file. This is an object
with field names corresponding to each calculation_name on that sheet. The values
for these fields are objects corresponding to the data-row matching that setting name.
• section_names – an array of the survey sections from the XLSX file. This includes
the synthesized initial sheet if one is not explicitly specified.
• sections – an object with field names corresponding to each of the section_names.
Each such field defines the form content for that section (that sheet in the XLSX file).
After the builder has processed the form definition, the following fields are added:
• currentPromptTypes – a list of all standard and custom Backbone prompt classes.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 441
Chapter 4. Trying It Out
sections Sub-Component
Each section object in the sections sub-component contains a heavily processed and cross-
checked version of that section of the survey. These objects have the following fields:
• section_name – the section name – i.e., the name of the sheet in the original XLSX
file.
• nested_sections – a map of all the section names that are targets of do_section
actions within this section.
442 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
• reachable_sections – a map that is the closure of all section names that can be
recursively reached by all nested sections and by this section. This is used to ensure
there are no cycles among the sections.
• prompts – a list of all prompts within this section.
• validation_tag_map – a map of all validation tag names and the array of prompts
that reference that tag name (and that have value constraints). Prompts can specify a
list of validation tag names that will enforce the prompt’s constraints by specifying a
space-separated list of values for a validation_tags column in their XLSX sheet. Inter-
mediate validation of some prompt values can be achieved via the validate {tagName}
action at any point in a survey. If nothing is specified for the validation_tags column,
the prompt is automatically added to the finalize validation tag, which is processed
when the Save as Complete action is initiated within the form.
• operations – an array of operations that the controller iterates through to process
this section of the form. Unless otherwise specified, processing starts at index zero in
this array.
• branch_label_map – a map of all branch (go-to) label names and the index within
the operation array to which they correspond. Used to map the ’goto label’ operation
to a destination within the operations array.
After the builder has processed the form definition, the following fields are added:
• parsed_prompts – a list of Backbone instances corresponding to the extension of
the referenced Backbone prompt type with the field values found in the prompts list.
And builder also scans the operations list applying the column_types rules.
During form navigation, the parsed_prompts list of Backbone instances will be used to render
DOM content and handle events. _The prompts array may be removed by the builder
in some future release._ Each of these prompts has an XLSXConverter-generated field,
_branch_label_enclosing_screen that identifies the branch label for the operation that will
render the screen containing this prompt. This is used during validation to map back from
the prompt whose constraints are violated to the begin_screen operation that will render the
screen containing that prompt. Prompts also have _row_num and __rowNum_ fields that
reference the XLSX row in the section that defines the prompt and the line number within
the section (one less than the XLSX row number due to the presence of the header row),
respectively. These are used for reporting exceptions during form loading and processing
(i.e., malformed formulas, etc.).
operations Sub-Sub-Element
Each element in the operations array describes an action the controller should execute when
processing the form. The 10 primitive operation types were described in an earlier section.
Below are brief examples of these various primitive operations.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 443
Chapter 4. Trying It Out
assign
assign actions can appear within begin screen … end screen regions or outside of them. If
they appear outside of them, they are interpreted as a separate operation by the controller.
Here is an example of such an assign action:
{
"type": "assign",
"name": "default_rating",
"calculation": 8,
"_row_num": 2,
"__rowNum__": 1,
"_token_type": "assign",
"operationIdx": 0
},
begin_screen
{
"clause": "begin screen",
"_row_num": 20,
"__rowNum__": 19,
"_token_type": "begin_screen",
"_end_screen_clause": {
444 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
,→today')));\nactivePromptIndicies.push(11);\n\nreturn activePromptIndicies;\n}\n
,→",
"operationIdx": 22
},
{
"_row_num": 2,
"_token_type": "begin_screen",
"_screen_block": "function() {var activePromptIndicies = [];
,→\nactivePromptIndicies.push(0);\n\nreturn activePromptIndicies;\n}\n",
"operationIdx": 0
},
goto_label
If-then-else clauses outside of begin screen … end screen regions are converted into branch
labels and conditional and unconditional goto_label commands. Additionally, users may
explicitly jump to a label using a goto clause in the XLSX file (and do that conditionally if
they specify a condition predicate). Here is an example of a conditional goto_label operation
object generated from an if clause.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 445
Chapter 4. Trying It Out
{
"clause": "if",
"condition": "selected(data('examples'), 'intents')",
"_row_num": 4,
"__rowNum__": 3,
"_token_type": "goto_label",
"_branch_label": "_then4",
"operationIdx": 2
},
{
"clause": "end if",
"_token_type": "goto_label",
"_branch_label": "_else9",
"_row_num": 9,
"operationIdx": 3
},
do_section
{
"clause": "do section household",
"_row_num": 2,
"__rowNum__": 1,
"_token_type": "do_section",
"_do_section_name": "household",
"operationIdx": 0
},
446 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
exit_section
{
"_token_type": "exit_section",
"clause": "exit section",
"_row_num": 7,
"operationIdx": 3
},
back_in_history
This is primarily used as a pseudo-instruction (an instruction injected into the operation
stream) when the user hits the Back button or swipes backward. This is also emitted as a
real operation when a back clause is specified in the XLSX file. Used in that manner, it can
create a ”dead-end” screen that the user cannot swipe through (they can only go backward)
and can be useful when presenting a user with a user_branch prompt (where the user must
choose the next action and there is no default action).
{
"clause": "back",
"_row_num": 4,
"__rowNum__": 3,
"_token_type": "back_in_history",
"operationIdx": 3
},
advance
This is only used as a pseudo-instruction (an instruction injected into the operation stream)
when the user hits the Next button or swipes forward.
validate
{
"clause": "validate user_info",
"_row_num": 12,
"__rowNum__": 11,
"_token_type": "validate",
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 447
Chapter 4. Trying It Out
"_sweep_name": "user_info",
"operationIdx": 7
},
Partial validation of a form is one of the advanced features of Survey. In this instance, only
the fields tagged with the user_info validation tag will be verified. The key field for this
operation is:
_sweep_name – the name of a validation tag. Any fields that have this name in
their space-separated list of validation tags under the validation_tags column in
the XLSX file will have their constraints validated.
If a field has a constraint but no values under the validation_tags column, finalize will
automatically be assumed to be in that list. ’validate finalize’ is called when a form is
saved-as-complete.
resume
None of our examples explicitly use this clause in the XLSX file. However, it is used in the
construction of the default Contents screen handler for a section which is emitted if the form
designer did not specify their own ’_contents’ branch label and define their own screen for this
purpose. Choosing to view the contents screen causes a jump to the ’_contents’ branch. The
default implementation of that branch is a begin_screen operation to display the Contents
screen followed by a resume. The default Contents screen has its hideInBackHistory field set
to true. This causes that screen to not be saved in the back history. When a user swipes
forward, the resume operation will scan backward to the screen before the Contents screen
(since it is skipped) and will render that screen (returning the user to the screen they were
last at).
{
"_token_type": "resume",
"clause": "resume",
"_row_num": 9,
"operationIdx": 12
}
save_and_terminate
This is not explicitly used in our examples, but it is used within the automatically-generated
’initial’ section if the user has not defined their own. This operation corresponds to a ’save
and terminate’ clause. That clause takes a ’condition’ expression that indicates whether
the content should be saved-as-complete or saved-as-incomplete (this clause does not itself
determine the validation status and hence completeness of the data). Because of this, any
448 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
save-as-complete action should be preceded by a ’validate finalize’ clause to ensure that the
form is validated. After saving the form contents, the Survey window is then closed.
{
"_token_type": "save_and_terminate",
"clause": "save and terminate",
"calculation": true,
"_row_num": 9,
"screen": {
"hideInBackHistory": true
},
"operationIdx": 11
},
Introduction
This document summarizes the API and the usage of the API. The URLs for the REST API
have a common URL prefix. E.g.,
• https://hostname:port/path/of/prefix/
That is assumed to be supplied by a configuration setting.
When describing the REST URL, path elements surrounded by curly braces ({}) indicate
the use of the value for that term in that location within the path. There are a handful of
these substitution terms used within the REST URLs. The most common of these are:
• appId– identifies the ’application’, which is a collection of configuration files and data
tables that provide a self-contained user experience. e.g., a survey campaign, a specific
set of workflows, etc. Applications live on the Android device under different subdi-
rectories within the /sdcard/opendatakit directory. The name of the subdirectory is
the appId of the application contained in the directory. The default application, with
an appId of default lives under the /sdcard/opendatakit/default/ directory.
• odkClientVersion – the ”major version” of ODK-X software on the device. This is the
100’s digit of the Android manifest version code. Also referred to as the ”rev number”
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 449
Chapter 4. Trying It Out
of the release. I.e., for rev 206, the odkClientVersion would be 2. Non-backward-
compatible changes to the JS API would bump this up. It allows groups to maintain
and move across incompatible API changes by supporting different versions of the
formDef.json, HTML and JS configuration files. Until we reach a release candidate,
we are not strictly tracking non-backward-compatible client versions. The exception
being the transition from jQuery-mobile-based JavaScript (version 1) and the current
bootstrap-based JavaScript (version 2).
• tableId – identifies a particular data table.
• schemaETag – identifies a particular manifestation of a table. If you drop the table and
recreate it, the re-creation will have a different schemaETag that the original table,
even if it is otherwise identical. In contrast, adding, updating or deleting individual
rows in a table does not change the schemaETag for that table.
• rowId – the primary key for a particular row within a table.
• rowETag – identifies a particular revision of a row within a table.
When defining the REST API, we use modified version of the JAX-RS annotations to de-
scribe the interface. For example, the API to create a table on the server is described as:
@PUT
@Path("{appId}/tables/{tableId}")
@Consumes({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*TableResource*/ createTable(TableDefinition definition)
throws ODKDatastoreException,
TableAlreadyExistsException,
PermissionDeniedException,
ODKTaskLockException;
@PUT, @POST, @GET and @DELETE indicate the type of HTTP request.
@Path indicates the URL path to invoke this method, with the curly brace substitutions of
the indicated substitution terms. This is appended to the common URL prefix provided by
the configuration setting.
@Consumes indicates the mime types of message bodies accepted by the server. In general,
the server accepts JSON and XML in UTF-8 format; JSON is preferred.
@Produces indicates the mime types of the message bodies returned to the client. In general,
the server can return JSON or XML in UTF-8 format; JSON is preferred.
The method may have zero or more arguments qualified by @QueryParam(...). These
identify query parameters for the request, with the … indicating the query parameter name.
450 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
Methods with entity bodies (PUT and POST methods) will generally have an additional
unqualified argument that identifies the content of that entity body. In our documentation,
this will generally be a Java class that uses Jackson2 parsers to marshal its content into or
out of XML or JSON representations (in the above example, the body of the HTTP PUT
request is a TableDefinition object).
The return type is indicated in a comment. The Response return type is a generic response
type that encapsulates both the successful return type (TableResource in this example) and
the error codes for the various exceptions. As this API gets fleshed out, the error codes for
each specific exception will be documented at the bottom of this page.
In general, the server supports GZIP compression of entity bodies in both directions.
Requests should specify 3 or 4 headers:
• X-OpenDataKit-Version – this should be set to 2.0
• X-OpenDataKit-Installation-Id – this should be set to a UUID that identifies
this client device. This UUID will generally be generated on first install of the ODK
Services APK. Using ”Clear Data” in the device settings will cause a new UUID to be
generated. This is used to track the devices responsible for changes to the configuration
(resetting the server) and for tracking the status of all devices as they synchronize with
the server.
• User-Agent – this is required by Google App Engine infrastructure before it will honor
requests for GZIP content compression of response entities (i.e., it ignores ”Accept-
Encoding” directives on requests if this is not present). The value supplied must end
with ” (gzip)”. Services uses a value of: ”Sync ” + versionCode + ” (gzip)” where
versionCode is is the revision code of the software release (e.g., 210). While optional,
it is highly recommended that all requests supply this header.
• Accept-Encoding – this should be set to ”gzip” when an entity body is returned.
We use Jackson 2.0 for transforming Java objects to and from XML and JSON representa-
tions. To understand the representations, it is best to use curl or any other REST client to
send requests to the server and view the returned structures.
In the following presentation, we provide the Jackson 2.0 annotations used in our code.
Data Groupings
Before discussing the API, it is useful to identify the data on the system. The ODK-X tools
assume all data fall into one of six groupings:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 451
Chapter 4. Trying It Out
1. (Data Grouping #1) HTML, JavaScript and tool configuration files that are not
specific to any data table. These include custom home screens, CSS, logo icons, and
settings for the tools (e.g., default font size, what settings options to show or hide).
2. (Data Grouping #2) Data table definition, properties, HTML and JavaScript asso-
ciated with a specific data table. These include all ODK Survey forms used to create
or edit this data table, ODK Tables HTML and CSS files for list views, map displays
and graphical displays of the data, and ODK Scan mark-sense form definitions.
3. (Data Grouping #3) Data rows and the file attachments (e.g., images, audio, video
or other files) associated with specific revision(s) of each data row.
4. Other files and data that are not synchronized with the server and are for internal use
only; e.g., the tools’ internal configuration files and device-specific configuration.
5. Other files that are not synchronized with the server but are generated for external use
such as exported csv files and detailed log files for troubleshooting.
6. content that is independently downloaded and managed by other means (e.g., cached
map tiles). I.e., this is content that is not synchronized with the server via the Syn-
chronization REST API.
A directory hierarchy and naming convention partitions files into each of the above 6 group-
ings. This is described here.
The mapping of these directories to the 3 data groupings that are synchronized with the
server through the Synchronization REST API are as follows:
All table-level configuration files (Data Grouping #2) are either located under:
• .../config/tables/tableId/
Or, they are files or directories under the csv folder:
• .../config/assets/csv/tableId.csv
• .../config/assets/csv/tableId/*
• .../config/assets/csv/tableId.qualifier.csv
• .../config/assets/csv/tableId.qualifier/*
Note that the file:
• .../config/tables/tableId/definition.csv
Defines the schema for the table. This is stored on the server, but is not verified against
the schema as created through the create-table REST API. This file is only processed when
initializing a device database from content pushed from app-designer.
452 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 453
Chapter 4. Trying It Out
8. leave any tables that are on the device but not on the server untouched (do not delete
them). By removing the configuration files for this table, it becomes invisible to users.
for each table on the device that is not on the server, delete that table and its table-
specific files ( (Data Grouping #2 part B). After this step, the table configuration
on the device exactly matches that of the server.
9. for each table, perform a bi-directional sync of the data and file attachments for the
rows of that table (Data Grouping #3). Log the device’s table-level synchronization
status for these tables after processing each table.
10. report overall information about the device’s synchronization status and information
about the device model, etc. at the end of the synchronization interaction.
@GET
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*AppNameList*/ getAppNames()
throws AppNameMismatchException,
PermissionDeniedException,
ODKDatastoreException;
@JacksonXmlRootElement(localName="appNames")
public class AppNameList extends ArrayList<String> {
}
Authenticate user
@GET
@Path("{appId}/privilegesInfo")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*PrivilegesInfo*/ getPrivilegesInfo()
throws AppNameMismatchException,
PermissionDeniedException,
ODKDatastoreException,
ODKTaskLockException;
454 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
@JacksonXmlRootElement(localName="privilegesInfo")
public class PrivilegesInfo {
/**
* User id -- this may be more fully-qualified than the user identity␣
,→information
* that the client used for login (the server may have provided auto-
,→completion
/**
* Friendly full name for this user. Could be used for display.
*/
@JsonProperty(required = false)
private String full_name;
/**
* Default group
*/
@JsonProperty(required = false)
private String defaultGroup;
/**
* The roles and groups this user belongs to.
* This is sorted alphabetically.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 455
Chapter 4. Trying It Out
*/
@JsonProperty(required = false)
@JacksonXmlElementWrapper(useWrapping=false)
@JacksonXmlProperty(localName="roles")
private ArrayList<String> roles
}
@GET
@Path("{appId}/usersInfo")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*UserInfoList*/ getUsersInfo()
throws AppNameMismatchException,
PermissionDeniedException,
ODKDatastoreException,
ODKTaskLockException;
This list may or may not be pruned based upon the privileges of the requesting user. i.e.,
unprivileged users might only see themselves in this list.
This list is useful if the requesting user has the privileges needed to alter the permissions
columns of a table’s row. They can use this list to select the user to assign ownership to
based upon the user’s friendly name (full_name) instead of the user_id (the internal string
identifying that user), etc.
The UserInfoList and UserInfo objects are defined as:
@JacksonXmlRootElement(localName="userInfoList")
public class UserInfoList extends ArrayList<UserInfo> {
}
and
@JacksonXmlRootElement(localName="userInfo")
public class UserInfo {
/**
* user id (unique)
*/
@JsonProperty(required = true)
private String user_id;
456 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
/**
* display name of user (may not be unique)
*/
@JsonProperty(required = true)
private String full_name;
/**
* The privileges this user has.
* Sorted.
*/
@JsonProperty(required = true)
@JacksonXmlElementWrapper(useWrapping=false)
@JacksonXmlProperty(localName="roles")
private ArrayList<String> roles;
}
@GET
@Path("{appId}/clientVersions")
@Produces({"application/json",
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 457
Chapter 4. Trying It Out
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*ClientVersionList*/ getOdkClientVersions()
throws AppNameMismatchException,
PermissionDeniedException,
ODKDatastoreException,
ODKTaskLockException;
This returns a list of the odkClientVersion values supported by this server. This is used
to fast-fail a synchronization attempt against a server when that server does not have any
configuration suitable for the indicated odkClientVersion. This commonly happens when an
application designer intends to reset the app server with their configuration files, but instead
syncs.
Note: Resetting the application server for a ’3’ client version will not damage or alter the
’2’ client version files. As long as the data table structures are not altered, the two client
versions can coexist on the server.
@JacksonXmlRootElement(localName="clientVersions")
public class ClientVersionList extends ArrayList<String> {
}
@GET
@Path("{appId}/manifest/{odkClientVersion}")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*OdkTablesFileManifest*/ getAppLevelFileManifest();
Requests the manifest of all app-level files for an appId and odkClientVersion.
The data structure returned is:
@JacksonXmlRootElement(localName="manifest")
public class OdkTablesFileManifest {
/**
* The entries in the manifest.
458 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
and here:
public class OdkTablesFileManifestEntry {
/**
* This is the name of the file relative to
* the either the 'config' directory (for
* app-level and table-level files) or the
* row's attachments directory (for row-level
* attachments).
*
* I.e., for the new directory structure,
* if the manifest holds configpath files, it is under:
* /sdcard/opendatakit/{appId}/config
* if the manifest holds rowpath files, it is under:
* /sdcard/opendatakit/{appId}/data/attachments/{tableId}/{rowId}
*/
public String filename;
@JsonProperty(required = false)
public Long contentLength;
@JsonProperty(required = false)
public String contentType;
/**
* This is the md5hash of the file, which will be used
* for checking whether or not the version of the file
* on the phone is current.
*/
@JsonProperty(required = false)
public String md5hash;
/**
* This is the url from which the current version of the file can be
* downloaded.
*/
@JsonProperty(required = false)
public String downloadUrl;
}
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 459
Chapter 4. Trying It Out
{
"files": [
{
"filename": "assets\/app.properties",
"contentLength": 730,
"contentType": "application\/octet-stream",
"md5hash": "md5:aa47d6c0c2b63a5b99c54e5b2630be42",
"downloadUrl": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→files\/2\/assets\/app.properties"
},
{
"filename": "assets\/changeAccessFilters.html",
"contentLength": 3202,
"contentType": "text\/html",
"md5hash": "md5:78d7402bdab8709b7c35d59ac7048689",
"downloadUrl": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→files\/2\/assets\/changeAccessFilters.html"
},
...
]
}
<?xml version="1.0"?>
<manifest>
<file>
<filename>assets/app.properties</filename>
<contentLength>730</contentLength>
<contentType>application/octet-stream</contentType>
<md5hash>md5:aa47d6c0c2b63a5b99c54e5b2630be42</md5hash>
<downloadUrl>https://msundt-test.appspot.com:443/odktables/default/files/
,→2/assets/app.properties</downloadUrl>
</file>
<file>
<filename>assets/changeAccessFilters.html</filename>
<contentLength>3202</contentLength>
<contentType>text/html</contentType>
<md5hash>md5:78d7402bdab8709b7c35d59ac7048689</md5hash>
<downloadUrl>https://msundt-test.appspot.com:443/odktables/default/files/
,→2/assets/changeAccessFilters.html</downloadUrl>
</file>
</manifest>
460 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
@GET
@Path("{appId}/files/{odkClientVersion}/{filePath:.*}")
@Produces({"*"})
public Response getFile(@QueryParam("as_attachment") String asAttachment)
throws IOException, ODKTaskLockException;
@POST
@Path("{appId}/files/{odkClientVersion}/{filePath:.*}")
@Consumes({"*"})
public Response putFile(byte[] content)
throws IOException, ODKTaskLockException;
This API is only used for updating the server configuration. During the normal client
synchronization workflow, this API is not invoked.
@DELETE
@Path("{appId}/files/{odkClientVersion}/{filePath:.*}")
public Response deleteFile()
throws IOException, ODKTaskLockException;
This API is only used for updating the server configuration. During the normal client
synchronization workflow, this API is not invoked.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 461
Chapter 4. Trying It Out
Data Grouping #2 REST Synchronization – Table API and Table Definition API
The table APIs manipulate TableResource objects and lists. A TableResource identifies the
table, information about the earliest and latest update to the data rows in the table, and
the schemaETag for the table.
The server generates a new, unique, schemaETag every time it creates or modifies the table
schema. If you create a table, destroy it, then re-create it, the new table will be given a new
schemaETag.
Creating a table registers a TableDefinition for that dataset with the server and creates the
necessary database tables for it. Using the schemaETag, clients can request the TableDef-
initionResource for any dataset on the server; that resource consists of the TableDefinition
and additional information.
Deleting a table on the server involves deleting the specific TableDefinition for that tableId’s
current schemaETag.
To prevent data loss, clients that encounter an unexpected schemaETag should sync their
data as if for the first time.
@GET
@Path("{appId}/tables")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*TableResourceList*/ getTables(@QueryParam("cursor") String␣
,→cursor, @QueryParam("fetchLimit") String fetchLimit)
throws ODKDatastoreException,
AppNameMismatchException,
PermissionDeniedException,
ODKTaskLockException;
If the server does not return the entire set of tables, it will provide a resumeParameter in
the TableResourceList that can be passed in as a query parameter for subsequent requests.
.. _sync-protocol-rest-sync-api-2-table-api-get-resources:
@GET
@Path("{appId}/tables/{tableId}")
@Produces({"application/json",
"text/xml;charset=UTF-8",
462 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
"application/xml;charset=UTF-8"})
public Response /*TableResource*/ getTable()
throws ODKDatastoreException,
AppNameMismatchException,
PermissionDeniedException,
ODKTaskLockException,
TableNotFoundException;
@PUT
@Path("{appId}/tables/{tableId}")
@Consumes({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*TableResource*/ createTable(TableDefinition definition)
throws ODKDatastoreException,
AppNameMismatchException,
TableAlreadyExistsException,
PermissionDeniedException,
ODKTaskLockException,
IOException;
@GET
@Path("{appId}/tables/{tableId}/ref/{schemaETag}")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*TableDefinitionResource*/ getDefinition()
throws ODKDatastoreException,
AppNameMismatchException,
PermissionDeniedException,
ODKTaskLockException,
TableNotFoundException;
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 463
Chapter 4. Trying It Out
@DELETE
@Path("{appId}/tables/{tableId}/ref/{schemaETag}")
public Response /*void*/ deleteTable()
throws ODKDatastoreException,
AppNameMismatchException,
ODKTaskLockException,
PermissionDeniedException;
@JacksonXmlRootElement(localName="tableResourceList")
public class TableResourceList {
/**
* pass this in to return this same result set.
*/
@JsonProperty(required = false)
private String webSafeRefetchCursor;
/**
* Alternatively, the user can obtain the elements preceding the contents of the
* result set by constructing a 'backward query' with the same filter criteria
* but all sort directions inverted and pass the webSafeBackwardCursor
* to obtain the preceding elements.
*/
@JsonProperty(required = false)
private String webSafeBackwardCursor;
/**
* together with the initial query, pass this in to
* return the next set of results
*/
@JsonProperty(required = false)
private String webSafeResumeCursor;
@JsonProperty(required = false)
private boolean hasMoreResults;
@JsonProperty(required = false)
private boolean hasPriorResults;
/**
* The entries in the manifest.
464 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
/**
* If known, the ETag of the app-level files
* manifest is also returned.
*/
@JsonProperty(required = false)
private String appLevelManifestETag;
}
@JacksonXmlRootElement(localName="tableResource")
public class TableResource extends TableEntry {
/**
* URLs for various other parts of the API
*/
/**
* Get this same TableResource.
*/
private String selfUri;
/**
* Get the TableDefinition for this tableId
*/
private String definitionUri;
/**
* Path prefix for data row interactions
*/
private String dataUri;
/**
* Path prefix for data row attachment interactions
*/
private String instanceFilesUri;
/**
* Path prefix for differencing (changes-since) service.
*/
private String diffUri;
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 465
Chapter 4. Trying It Out
/**
* Path prefix for permissions / access-control service.
*/
private String aclUri;
/**
* table-level file manifest ETag (optional)
*/
@JsonProperty(required = false)
private String tableLevelManifestETag;
}
and
public class TableEntry implements Comparable<TableEntry> {
/**
* The tableId this entry describes.
*/
private String tableId;
/**
* The ETag of the most recently modified data row
*/
@JsonProperty(required = false)
private String dataETag;
/**
* The ETag of the TableDefinition
*/
@JsonProperty(required = false)
private String schemaETag;
}
,→yKAfmsuZb2BGHi0ZTYPbpe3MfFgzX2MhnHOevmJXAsO5YU9TJXpwqCQwU3OwjFu4oCrSbJnk6922WCT5Uorv9A3vobWoQ
,→Ixn40Dv08DOJwFk8ibzaZjvyHPro9LC01GzCcIVvqsOzdCrVD4BpJir-AbMxKkwMq0-dkdYLWoBS_
,→tnxdUne9OG7_BAEAAA",
"webSafeResumeCursor":
,→"H4sIAAAAAAAAAG2PzQrCMBCEX0W8Spu2osUSA1IVBKkgxWuJ7VKDNZHNhvj4ihX8wTnOfAMzvHZoDQ5ul07b-
,→fBEdM0Y896H5gq6kSTPikKDLevBoeCSCNXRERTyAqLK96tFudkV1XJRrjj7Tt_
,→wQXYORBLFaRClQRKVSZwl02wyDuN4Nooe-uj2MHeottLSHsihhqZ3WzAeJJ0Aq9roRpEy2nL2l-
,→XKrg16iU3-XC8IHXD26_LXOXEHZEOUAg4BAAA",
466 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
"hasMoreResults": false,
"hasPriorResults": false,
"tables": [
{
"tableId": "geoweather",
"dataETag": "uuid:d74fb991-850a-4a4c-add5-858690b97c81",
"schemaETag": "uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8",
"selfUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather",
"definitionUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/
,→default\/tables\/geoweather\/ref\/uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8",
"dataUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather\/ref\/uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8\/rows",
"instanceFilesUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/
,→default\/tables\/geoweather\/ref\/uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8\/
,→attachments",
"diffUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather\/ref\/uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8\/diff",
"aclUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather\/acl",
"tableLevelManifestETag": "19260e15"
},
{
"tableId": "geoweather_conditions",
"dataETag": "uuid:e93ead34-8ee1-4c5c-9d25-7732a5ec9c96",
"schemaETag": "uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1",
"selfUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions",
"definitionUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/
,→default\/tables\/geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-
,→ac6cd8bf98b1",
"dataUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1\/
,→rows",
"instanceFilesUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/
,→default\/tables\/geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-
,→ac6cd8bf98b1\/attachments",
"diffUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1\/
,→diff",
"aclUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions\/acl",
"tableLevelManifestETag": "75a915a5"
}
],
"appLevelManifestETag": "eded21dd"
}
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 467
Chapter 4. Trying It Out
,→yKAfmsuZb2BGHi0ZTYPbpe3MfFgzX2MhnHOevmJXAsO5YU9TJXpwqCQwU3OwjFu4oCrSbJnk6922WCT5Uorv9A3vobWoQ
,→Ixn40Dv08DOJwFk8ibzaZjvyHPro9LC01GzCcIVvqsOzdCrVD4BpJir-AbMxKkwMq0-dkdYLWoBS_
,→tnxdUne9OG7_BAEAAA</webSafeBackwardCursor>
<webSafeResumeCursor>
,→H4sIAAAAAAAAAG2PzQrCMBCEX0W8Spu2osUSA1IVBKkgxWuJ7VKDNZHNhvj4ihX8wTnOfAMzvHZoDQ5ul07b-
,→fBEdM0Y896H5gq6kSTPikKDLevBoeCSCNXRERTyAqLK96tFudkV1XJRrjj7Tt_
,→wQXYORBLFaRClQRKVSZwl02wyDuN4Nooe-uj2MHeottLSHsihhqZ3WzAeJJ0Aq9roRpEy2nL2l-
,→XKrg16iU3-XC8IHXD26_LXOXEHZEOUAg4BAAA</webSafeResumeCursor>
<hasMoreResults>false</hasMoreResults>
<hasPriorResults>false</hasPriorResults>
<appLevelManifestETag>eded21dd</appLevelManifestETag>
<tableResource>
<tableId>geoweather</tableId>
<dataETag>uuid:d74fb991-850a-4a4c-add5-858690b97c81</dataETag>
<schemaETag>uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8</schemaETag>
<selfUri>https://msundt-test.appspot.com:443/odktables/default/tables/
,→geoweather</selfUri>
<definitionUri>https://msundt-test.appspot.com:443/odktables/default/
,→tables/geoweather/ref/uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8</definitionUri>
<dataUri>https://msundt-test.appspot.com:443/odktables/default/tables/
,→geoweather/ref/uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8/rows</dataUri>
<instanceFilesUri>https://msundt-test.appspot.com:443/odktables/default/
,→tables/geoweather/ref/uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8/attachments</
,→instanceFilesUri>
<diffUri>https://msundt-test.appspot.com:443/odktables/default/tables/
,→geoweather/ref/uuid:eb4e7240-af0c-4ccb-abc5-4e537a4609f8/diff</diffUri>
<aclUri>https://msundt-test.appspot.com:443/odktables/default/tables/
,→geoweather/acl</aclUri>
<tableLevelManifestETag>19260e15</tableLevelManifestETag>
</tableResource>
<tableResource>
<tableId>geoweather_conditions</tableId>
<dataETag>uuid:e93ead34-8ee1-4c5c-9d25-7732a5ec9c96</dataETag>
<schemaETag>uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1</schemaETag>
<selfUri>https://msundt-test.appspot.com:443/odktables/default/tables/
,→geoweather_conditions</selfUri>
<definitionUri>https://msundt-test.appspot.com:443/odktables/default/
,→tables/geoweather_conditions/ref/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1</
,→definitionUri>
<dataUri>https://msundt-test.appspot.com:443/odktables/default/tables/
,→geoweather_conditions/ref/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1/rows</
,→dataUri>
468 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
<instanceFilesUri>https://msundt-test.appspot.com:443/odktables/default/
,→ tables/geoweather_conditions/ref/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1/
,→attachments</instanceFilesUri>
<diffUri>https://msundt-test.appspot.com:443/odktables/default/tables/
,→geoweather_conditions/ref/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1/diff</
,→diffUri>
<aclUri>https://msundt-test.appspot.com:443/odktables/default/tables/
,→geoweather_conditions/acl</aclUri>
<tableLevelManifestETag>75a915a5</tableLevelManifestETag>
</tableResource>
</tableResourceList>
@JacksonXmlRootElement(localName="tableDefinition")
public class TableDefinition {
/**
* Schema version ETag for the tableId's database schema.
*/
@JsonProperty(required = false)
private String schemaETag;
/**
* Unique tableId
*/
private String tableId;
/**
* The columns in the table.
*/
@JsonProperty(required = false)
@JacksonXmlElementWrapper(localName="orderedColumns")
@JacksonXmlProperty(localName="column")
private ArrayList<Column> orderedColumns;
}
@JacksonXmlRootElement(localName="tableDefinitionResource")
public class TableDefinitionResource extends TableDefinition {
/**
* Get this same TableDefinitionResource.
*/
private String selfUri;
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 469
Chapter 4. Trying It Out
/**
* Get the TableResource for this tableId.
*/
private String tableUri;
}
The configpath type’s value is relative to the config directory. The ’rowpath’ type’s value is
relative to the directory in which a rowId attachments are stored.
with columns defined by:
/**
* The name by which this element is referred. For composite types whose
* elements are individually retained (e.g., geopoint), this would be simply
* 'latitude'
*
* Never longer than 58 characters.
* Never a SQL or SQLite reserved word
* Satisfies this regex: '^\\p{L}\\p{M}*(\\p{L}\\p{M}*|\\p{Nd}|_)*$'
*/
@JsonProperty(required = false)
private String elementName;
/**
* This is the ColumnType of the field. It is either:
* boolean
* integer
* number
* configpath
470 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
* rowpath
* array
* array(len)
* string
* string(len)
* typename
* typename(len)
*
* or
*
* typename:datatype
* typename:datatype(len)
*
* where datatype can be one of boolean, integer, number, array, object
*
* Where:
*
* 'typename' is any other alpha-numeric name (user-definable data type).
*
* The (len) attribute, if present, identifies the VARCHAR storage
* requirements for the field when the field is a unit of retention.
* Ignored if not a unit of retention.
*
* The server stores:
*
* integer as a 32-bit integer.
*
* number as a double-precision floating point value.
*
* configpath indicates that it is a relative path to a file under the
,→'config'
* rooted from:
* /sdcard/opendatakit/{appId}/config/
*
* rowpath indicates that it is a relative path to a file under the row's␣
,→attachment
* rooted from:
* /sdcard/opendatakit/{appId}/data/attachments/{tableId}/
,→{rowId}/
*
* array is a JSON serialization expecting one child element key
* that defines the data type in the array. Array fields
* MUST be a unit of retention (or be nested within one).
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 471
Chapter 4. Trying It Out
*
* string is a string value
*
* anything else, if it has no child element key, it is a string
* (simple user-defined data type). Unless a datatype is specified.
*
* anything else, if it has one or more child element keys, is a
* JSON serialization of an object containing those keys
* (complex user-defined data type).
*
*/
private String elementType;
/**
* JSON serialization of an array of strings. Each value in the
* array identifies an elementKey of a nested field within this
* elementKey. If there are one or more nested fields, then the
* value stored in this elementKey is a JSON serialization of
* either an array or an object. Otherwise, it is either an
* integer, number or string field.
*
* If the elementType is 'array', the serialization is an
* array and the nested field is retrieved via a subscript.
*
* Otherwise, the serialization is an object and the nested
* field is retrieved via the elementName of that field.
*/
@JsonProperty(required = false)
private String listChildElementKeys;
}
472 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
"listChildElementKeys": "[]"
},
{
"elementKey": "Language",
"elementName": "Language",
"elementType": "string",
"listChildElementKeys": "[]"
}
],
"selfUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/tables\/
,→geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1",
"tableUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions"
@GET
@Path("{appId}/manifest/{odkClientVersion}/{tableId}")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*OdkTablesFileManifest*/ getTableIdFileManifest()
throws ODKEntityNotFoundException,
ODKOverQuotaException,
PermissionDeniedException,
ODKDatastoreException,
ODKTaskLockException;
The table-level files API is identical to the app-level files API. It relies upon the file naming
convention to distinguish between app-level files and table-level files.
BLOBs, long strings (e.g., MySQL TEXT fields) and arbitrary files can be associated with
any data row. These are stored as files and viewed as ’attachments’ of the row. If a row
has an attachment, the row is expected to have one or more columns in its data table that
contain the path to that attachment.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 473
Chapter 4. Trying It Out
For example, the ODK Tools use a rowpath elementType (see the Column object, presented
earlier), the attachment field definition in Survey (either an imageUri, audioUri or videoUri
object) consists of two parts, a uriFragment that is a rowpath elementType and a contentType
that is a string containing the mime type of the attachment. The rowpath is a path relative
to the storage location for files associated with this rowId. e.g.,
{ uriFragment: "filename.jpg",
contentType: "image/jpg" }
Revision States
It is assumed that the client maintains a set of revision states for an individual row. These
1. synced - no changes to an existing record obtained from the server and all attach-
ment changes have been handled.
2. new_row - a new record on the client.
3. changed - the client modified an existing record obtained from the server.
4. deleted - the client deleted an existing record obtained from the server.
5. synced_pending_files - the client considers the row data to be in the ’rest’ state,
but the attachments for this row may or may not be up-to-date.
6. in_conflict - the client has determined that there was both a local change to the
row and another client has pushed a change to the server, so that the local change
cannot be directly submitted to the server, but must instead be resolved with the
server’s version before being uploaded.
For a given tableId, whenever the schemaETag for that tableId has changed, if the client w
• reset all rows in the in_conflict state to their original local change status (i.e.,
one of new_row, changed or deleted),
• mark all synced and synced_pending_files rows as new_row.
• reset the table’s last-change-processed value so that the next sync of the table’s
data will attempt to sync every row in the table.
This may cause all the client’s rows to become in conflict with the server; it is unclear what
should be the default treatment for this condition.
The server maintains a full history of all changes to a given row. Each row is identified by
a rowId. Each row revision is identified by its (rowId, rowETag) tuple.
474 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
When a client row is synced with the server, the rowETag of the prior version of that rowId
is sent up to the server (sending null if this is an new_row row) along with all the values in
the row.
When a client row is in the new_row state, the client may optionally send null for the value
of the rowId, in which case the server will assign an id.
An insert-or-update row request is successful if:
• the rowId does not yet exist, or
• the rowETag matches the value for the most recent revision to rowId, or
• the rowETag doesn’t match, but the values of the most recent version of the rowId
on the server exactly match the values sent from the client.
A delete row request is successful if:
• the rowId does not yet exist, or
• the rowETag matches the value for the most recent revision to rowId
If successful, any changes are applied on the server, and the client is returned the updated
row (and updated rowETag). The client should then either delete the local copy if it was
in the deleted state, or update its corresponding row to synced_pending_files if there are
rowpath columns in the dataset or synced if not, and set rowETag to the value returned for
rowETag in the updated record.
If unsuccessful, an ETagMismatchException error is reported back to the client, and the client
should mark the row as in_conflict. in_conflict rows are not eligible to be synced until the
client resolves the conflict state, usually through processing convention or user intervention.
If the row is in the synced_pending_files state, then the client must determine what actions
it needs to perform to bring this row’s attachment(s) state into concordance with the server.
Because data records can be sent up to the server before their associated attachments are
sent, clients may obtain data records from the server that lack the attachment files that they
reference. I.e., ClientOne may sync a row with an updated attachment to the server, but
fail to send the attachment itself. ClientTwo may then sync with the server, obtain the row
updates that ClientOne just posted, and therefore have a valid, current, row without the
attachments that it references.
This is a normal condition and should be anticipated and gracefully handled by the client.
synced_pending_files treatment
There is a potential for loss of an earlier attachment if the data row is partially synced
(transitioning into synced_pending_files) and the data row is then updated, changing the
attachment, before the earlier version of the attachment is saved on the server.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 475
Chapter 4. Trying It Out
Because the client is strictly forbidden from modifying the contents of the attachment file,
we always know if a new attachment is created because the data row will always be modified
to update the attachment path.
Similarly, because the config directory is static and dictated by the server, any configpath
field in a data row does not require syncing of that referenced file with the server. It is
assumed that the server already has that file. Only the rowpath fields in a data row need to
have their attachments synced.
The server maintains a manifest of all rowpath attachments uploaded for all versions of the
row.
The current implementation only considers attachments specified in ’rowpath’ elements.
If the attachment has not yet been uploaded, a NOT_FOUND is returned should that
attachment be requested.
The sync mechanism first requests all rowpath files, either specifying an ETag if the file exists
locally, or omitting it, to pull the file. If a request with an ETag returns NOT_MODIFIED,
then the server has that file. If it returns NOT_FOUND, then the client should push the
file to the server. If it returns the file, then there is an exceptional condition and the client
should log an error (but it is fine to download the file – the server is still the authority for
what these files should contain).
476 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
7. If the above two stages complete without errors, resolve rows in the
synced_pending_files state by pushing / pulling attachments to / from the server.
If successful, transition that row into the synced state.
8. Report status metrics for this table to the server.
And, at some later time: * Resolve any in_conflict rows (user-directed) This conflict resolu-
tion will transition rows either into a state matching that on the server, or into an updated
changed state such that on the next synchronization those changes will be able to be suc-
cessfully pushed to the server (unless those rows were changed, yet again, by another client).
@GET
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/diff")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*RowResourceList*/ getRowsSince(@QueryParam("data_etag") String␣
,→dataETag, @QueryParam("cursor") String cursor, @QueryParam("fetchLimit")␣
,→String fetchLimit)
throws ODKDatastoreException,
PermissionDeniedException,
InconsistentStateException,
ODKTaskLockException, BadColumnNameException;
Unlike the other REST interfaces, this takes a query parameter specifying the dataETag
from which to report the set of changed rows.
If the server cannot return the entire set of rows, it will provide a resumeParameter in the
RowResourceList that can be passed in as a query parameter to generate the next grouping
of rows.
@GET
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/diff/changeSets")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*ChangeSetList*/ getChangeSetsSince(@QueryParam("data_etag")␣
,→String dataETag, @QueryParam("sequence_value") String sequenceValue)
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 477
Chapter 4. Trying It Out
@JacksonXmlRootElement(localName="changeSetList")
public class ChangeSetList {
/**
* The dataETag values.
*/
@JsonProperty(required = false)
@JacksonXmlElementWrapper(useWrapping=false)
@JacksonXmlProperty(localName="changeSet")
private ArrayList<String> changeSets;
/**
* The dataETag value of the table at the START of this request.
*/
@JsonProperty(required = false)
private String dataETag;
/**
* The sequenceValue of the server at the START of this request.
* A monotonically increasing string.
*/
@JsonProperty(required = false)
private String sequenceValue;
}
478 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
@GET
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/diff/changeSets/{dataETag}")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*RowResourceList*/ getChangeSetRows(@QueryParam("active_only")␣
,→String isActive,
@GET
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/rows")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*RowResourceList*/ getRows(@QueryParam("cursor") String cursor,␣
,→@QueryParam("fetchLimit") String fetchLimit)
If the server cannot return the entire set of rows, it will provide a resumeParameter in the
RowResourceList that can be passed in as a query parameter to generate the next grouping
of rows.
The RowResourceList returned contains the dataETag of the last change processed on the
server.
Note: Later requests with resume cursors may return different values for this dataETag..
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 479
Chapter 4. Trying It Out
The value in the first result should be compared with the value returned at the end of the
chain of requests. If this value does change, the client should update its table dataETag to
the first value and issue a new request using the first dataETag. This will pull the changes
that were occurring as the first result set was being pulled and processed by the client. Only
once the dataETag does not change can the client be assured that it does not have any
partial changeSets.
@GET
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/rows/{rowId}")
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*RowResource*/ getRow()
throws ODKDatastoreException,
PermissionDeniedException, InconsistentStateException,
ODKTaskLockException, BadColumnNameException;
@PUT
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/rows")
@Consumes({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
@Produces({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
public Response /*RowOutcomeList*/ alterRows(RowList rows)
throws ODKTaskLockException, ODKDatastoreException,
PermissionDeniedException, BadColumnNameException,
InconsistentStateException,␣
,→TableDataETagMismatchException;
This REST interface takes a RowList that must contain the dataETag of the table that
matches the one on the server. If the value does not match, the server returns 409 (CON-
FLICT) and the client should use the diff API to fetch changes from the server before
re-attempting to alter data on the server. If the dataETag does match, a RowOutcomeList
is returned with the actions taken by the server.
480 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
Warning: Some row changes may fail, and some may succeed (e.g., due to permissions
violations).
The client should process the RowOutcome information to update its local database to match
that on the server. For bandwidth efficiency, large portions of the RowOutcome object will
be null upon success.
The RowOutcomeList contains the dataETag of the resulting change set on the server. The
client should update its table dataETag to match this value.
/**
* The entries in the manifest.
*/
@JsonProperty(required = false)
@JacksonXmlElementWrapper(useWrapping=false)
@JacksonXmlProperty(localName="row")
private ArrayList<Row> rows;
/**
* The dataETag of the table at the START of this request.
*/
@JsonProperty(required = false)
private String dataETag;
}
/**
* The URL that returns the TableResource for this table.
*/
@JsonProperty(required = false)
private String tableUri;
/**
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 481
Chapter 4. Trying It Out
/**
* The dataETag for the changes made by this request.
*/
@JsonProperty(required = false)
private String dataETag;
}
/**
* The entries in the manifest.
*/
@JsonProperty(required = false)
@JacksonXmlElementWrapper(useWrapping=false)
@JacksonXmlProperty(localName="rowResource")
private ArrayList<RowResource> rows;
/**
* The dataETag of the table at the START of this request.
*/
@JsonProperty(required = false)
private String dataETag;
/**
* The URL that returns the TableResource for this table.
*/
private String tableUri;
/**
* together with the initial query, pass this in to
* return this same result set.
*/
@JsonProperty(required = false)
private String webSafeRefetchCursor;
/**
* Alternatively, the user can obtain the elements preceding the contents of␣
,→the
482 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
* result set by constructing a 'backward query' with the same filter criteria
* but all sort directions inverted and pass the webSafeBackwardCursor
* to obtain the preceding elements.
*/
@JsonProperty(required = false)
private String webSafeBackwardCursor;
/**
* together with the initial query, pass this in to
* return the next set of results
*/
@JsonProperty(required = false)
private String webSafeResumeCursor;
@JsonProperty(required = false)
private boolean hasMoreResults;
@JsonProperty(required = false)
private boolean hasPriorResults;
@JacksonXmlRootElement(localName="rowResource")
public class RowResource extends Row {
/**
* The URL that returns this RowResource.
*/
private String selfUri;
}
@JacksonXmlRootElement(localName = "rowResource")
public class RowOutcome extends Row {
/**
* Possible values:
* <ul>
* <li>UNKNOWN -- initial default value</li>
* <li>SUCCESS -- rowETag, dataETagAtModification, filterScope updated</li>
* <li>DENIED -- permission denied -- just the rowId is returned</li>
* <li>IN_CONFLICT -- server record is returned (in full)</li>
* <li>FAILED -- anonymous insert conflict (impossible?) or
* delete of non-existent row -- just rowId is returned</li>
* </ul>
*/
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 483
Chapter 4. Trying It Out
/**
* The URL that returns this RowResource.
*/
@JsonProperty(required = false)
private String selfUri;
@JsonProperty(required = false)
private OutcomeType outcome = OutcomeType.UNKNOWN;
}
/**
* PK identifying this row of data.
*/
@JacksonXmlProperty(localName = "id")
@JsonProperty(value = "id", required = false)
private String rowId;
/**
* identifies this revision of this row of data.
* (needed to support updates to data rows)
* (creation is a revision from 'undefined').
*/
@JsonProperty(required = false)
private String rowETag;
/**
* identifies the service-level
* interaction during which this
* revision was made. Useful for
* finding coincident changes
* and prior/next changes.
*/
@JsonProperty(required = false)
private String dataETagAtModification;
/**
* deletion is itself a revision.
*/
@JsonProperty(required = false)
484 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
/**
* audit field returned for
* archive/recovery tools.
*/
@JsonProperty(required = false)
private String createUser;
/**
* audit field returned for
* archive/recovery tools
*/
@JsonProperty(required = false)
private String lastUpdateUser;
/**
* OdkTables metadata column.
*
* The ODK Survey form that
* was used when revising this
* row.
*
* This can be useful for
* implementing workflows.
* I.e., if savepointTyp is
* COMPLETE with this formId,
* then enable editing with
* this other formId.
*/
@JsonProperty(required = false)
private String formId;
/**
* OdkTables metadata column.
*
* The locale of the device
* that last revised this row.
*/
@JsonProperty(required = false)
private String locale;
/**
* OdkTables metadata column.
*
* One of either COMPLETE
* or INCOMPLETE. COMPLETE
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 485
Chapter 4. Trying It Out
/**
* OdkTables metadata column.
*
* For Mezuri, the timestamp
* of this data value.
*
* For ODK Survey, the last
* save time of the survey.
*
* For sensor data,
* the timestamp for the
* reading in this row.
*/
@JsonProperty(required = false)
private String savepointTimestamp;
/**
* OdkTables metadata column.
*
* For ODK Survey, the user
* that filled out the survey.
*
* Unclear what this would be
* for sensors.
*
* For Mezuri, this would be
* the task execution ID that
* created the row.
*/
@JsonProperty(required = false)
private String savepointCreator;
/**
* RowFilterScope is passed down to device.
*
* Implements DEFAULT, MODIFY, READ_ONLY, HIDDEN
* with rowOwner being the "owner" of the row.
*
* It is passed down to the
486 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
/**
* Array of user-defined column name to
* the string representation of its value.
* Sorted by ascending column name.
*/
@JsonProperty(required = false)
@JacksonXmlElementWrapper(localName="orderedColumns")
@JacksonXmlProperty(localName="value")
private ArrayList<DataKeyValue> orderedColumns;
}
/**
* Type of Filter.
*
* Limited to 10 characters
*/
public enum Access {
FULL, MODIFY, READ_ONLY, HIDDEN,
}
@JsonProperty(required = false)
private Access defaultAccess;
@JsonProperty(required = false)
private String rowOwner;
@JsonProperty(required = false)
private String groupReadOnly;
@JsonProperty(required = false)
private String groupModify;
@JsonProperty(required = false)
private String groupPrivileged;
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 487
Chapter 4. Trying It Out
@JacksonXmlText
public String value;
}
{
"rows": [
{
"rowETag": "uuid:e818c096-c3c6-4ec6-ac40-015ddfbef303",
"dataETagAtModification": "uuid:e93ead34-8ee1-4c5c-9d25-7732a5ec9c96",
"deleted": false,
"createUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"lastUpdateUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"formId": "geoweather_conditions",
"locale": "en_US",
"savepointType": "COMPLETE",
"savepointTimestamp": "2017-07-21T19:13:52.594000000",
"savepointCreator": "username:msundt",
"orderedColumns": [
{
"column": "Code",
"value": "clear"
},
{
"column": "Description",
"value": "Clear skies on 5.0"
},
{
"column": "Language",
"value": "en"
}
],
"selfUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1\/
,→rows\/uuid:50caa4ef-4f7f-4229-80b6-8e2d44026b90",
"id": "uuid:50caa4ef-4f7f-4229-80b6-8e2d44026b90",
"filterScope": {
"defaultAccess": "FULL",
488 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
"rowOwner": null,
"groupReadOnly": null,
"groupModify": null,
"groupPrivileged": null
}
},
{
"rowETag": "uuid:a3a8e4b8-295c-410e-a9ec-7577e386799f",
"dataETagAtModification": "uuid:e93ead34-8ee1-4c5c-9d25-7732a5ec9c96",
"deleted": false,
"createUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"lastUpdateUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"formId": "geoweather_conditions",
"locale": "en_US",
"savepointType": "COMPLETE",
"savepointTimestamp": "2017-07-21T19:13:02.633000000",
"savepointCreator": "username:msundt",
"orderedColumns": [
{
"column": "Code",
"value": "rain"
},
{
"column": "Description",
"value": "Raining on 5.0"
},
{
"column": "Language",
"value": "en"
}
],
"selfUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1\/
,→rows\/uuid:7fba9aa0-df29-4e3b-a390-e07b4ee48fe8",
"id": "uuid:7fba9aa0-df29-4e3b-a390-e07b4ee48fe8",
"filterScope": {
"defaultAccess": "READ_ONLY",
"rowOwner": null,
"groupReadOnly": null,
"groupModify": null,
"groupPrivileged": null
}
},
{
"rowETag": "uuid:34847487-3f5d-4f66-814c-602e2dc4d6d2",
"dataETagAtModification": "uuid:e93ead34-8ee1-4c5c-9d25-7732a5ec9c96",
"deleted": false,
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 489
Chapter 4. Trying It Out
"createUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"lastUpdateUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"formId": "geoweather_conditions",
"locale": "en_US",
"savepointType": "COMPLETE",
"savepointTimestamp": "2017-07-21T19:14:32.127000000",
"savepointCreator": "username:msundt",
"orderedColumns": [
{
"column": "Code",
"value": "thunderstorm"
},
{
"column": "Description",
"value": "Thunderstorm on 5.0"
},
{
"column": "Language",
"value": "en"
}
],
"selfUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1\/
,→rows\/uuid:7fba9aa0-df29-4e3b-a390-e08b4ee48fe8",
"id": "uuid:7fba9aa0-df29-4e3b-a390-e08b4ee48fe8",
"filterScope": {
"defaultAccess": "READ_ONLY",
"rowOwner": null,
"groupReadOnly": null,
"groupModify": null,
"groupPrivileged": null
}
},
{
"rowETag": "uuid:9c13fa4c-62c0-4a53-9038-34514c9b17f0",
"dataETagAtModification": "uuid:e93ead34-8ee1-4c5c-9d25-7732a5ec9c96",
"deleted": false,
"createUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"lastUpdateUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"formId": "geoweather_conditions",
"locale": "en_US",
"savepointType": "COMPLETE",
"savepointTimestamp": "2017-07-21T19:12:36.747000000",
"savepointCreator": "username:msundt",
"orderedColumns": [
{
"column": "Code",
490 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
"value": "drizzle"
},
{
"column": "Description",
"value": "Light rain (drizzle) on 5.0"
},
{
"column": "Language",
"value": "en"
}
],
"selfUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1\/
,→rows\/uuid:88b2edbc-092a-44c2-9736-8d50f6e44704",
"id": "uuid:88b2edbc-092a-44c2-9736-8d50f6e44704",
"filterScope": {
"defaultAccess": "HIDDEN",
"rowOwner": null,
"groupReadOnly": null,
"groupModify": null,
"groupPrivileged": null
}
},
{
"rowETag": "uuid:82d61608-a870-4976-baa8-2c7af974f74e",
"dataETagAtModification": "uuid:e93ead34-8ee1-4c5c-9d25-7732a5ec9c96",
"deleted": false,
"createUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"lastUpdateUser": "uid:msundt|2014-10-03T16:48:04.320+0000",
"formId": "geoweather_conditions",
"locale": "en_US",
"savepointType": "COMPLETE",
"savepointTimestamp": "2017-07-21T19:15:04.655000000",
"savepointCreator": "username:msundt",
"orderedColumns": [
{
"column": "Code",
"value": "partly_cloudy"
},
{
"column": "Description",
"value": "Partly cloudy on 5.0"
},
{
"column": "Language",
"value": "en"
}
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 491
Chapter 4. Trying It Out
],
"selfUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions\/ref\/uuid:b48be1ae-d861-4453-97a2-ac6cd8bf98b1\/
,→rows\/uuid:999f57ec-d866-45bc-ad54-52c57489d54b",
"id": "uuid:999f57ec-d866-45bc-ad54-52c57489d54b",
"filterScope": {
"defaultAccess": "MODIFY",
"rowOwner": null,
"groupReadOnly": null,
"groupModify": null,
"groupPrivileged": null
}
}
],
"dataETag": "uuid:e93ead34-8ee1-4c5c-9d25-7732a5ec9c96",
"tableUri": "https:\/\/msundt-test.appspot.com:443\/odktables\/default\/
,→tables\/geoweather_conditions",
"webSafeRefetchCursor": null,
"webSafeBackwardCursor": "H4sIAAAAAAAAAG2PW4vCMBCF_
,→4r4KmnSUO2FGBB1YUFckLKvMjXT3WBtJZlQf_6W7YIX9jzMw5nvHDjqFJzv3OR2aVq_nH4TXQvO-
,→76Puiu2BgjOlqLOffERnGoFRM5WgXAPF9TH9WG7Kt8_9sfNqtwq_vy9w5_
,→QBNRSxCkTKZOilHEh00JkUT6PZ2LQQ3aEVXB2B54OSMG1aEY3BGuKuTgBJFizpE6HI2XOMlEtWIbSJImQiyof-
,→v7NK-vfOteDM-vfRbqGxqPir7b6W6x_ACeKKe0jAQAA",
"webSafeResumeCursor":
,→"H4sIAAAAAAAAAG2Py2rDMBREf6VkW2QpimVFRhWYPCBQUgimWyNbaiOS2OH6Cvfza-
,→pC0pJZDTNnFqObCH0HT1-Xc9u_
,→zI6I15zSYRiS7upbZ9GeAiYdfNIJnBltESHUEf3eXrypVodNUe7e9tW6KDea_
,→m1v8Ls9R284m0vCJOGs5POcy5yphPHFMxt1t51gHSG82h4PHiO03k1pjMHlSqkPIX1D3DLLSCrqhlgnUiJ4I2S6VKOvNX
,→p_r3sPkG0rFWryIBAAA",
"hasMoreResults": false,
"hasPriorResults": false
}
The dataETagAtModification field tracks the change entry that can be used with the Get
All Data Changes Since… API to return the changes in the data table from this row’s
last data change (as indicated by the rowETag).
The createUser and lastUpdateUser fields may be set and returned by the server. These are
intended for data-dump and data-restore functionality and are not normally provided by a
client.
The formId field identifies the ODK Survey form that last modified this record. This is
useful for implementing multi-stage client workflows.
The locale field tracks the last ODK Survey locale in which the form was opened and perhaps
modified.
492 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
This returns all attachments (both current and historical) for the given rowId on the server.
This uses the same return structure as the Table-level and App-level manifest, but the path
is relative to the directory in which the rowId attachments are stored on the client.
There is both a multipart file download/upload API and an individual-file download/upload
API. The Android client uses the multipart file API.
@POST
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/attachments/{rowId}/download")
@Consumes({"application/json",
"text/xml;charset=UTF-8",
"application/xml;charset=UTF-8"})
@Produces({"multipart/form-data"})
public Response getFiles(OdkTablesFileManifest manifest) throws IOException,␣
,→ODKTaskLockException, PermissionDeniedException;
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 493
Chapter 4. Trying It Out
To Do: verify that a part’s name is the filename relative to the folder holding attachments
for the rowId.
Returns a string describing error on failure, otherwise empty and Status.CREATED.
@GET
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/attachments/{rowId}/file/
,→{filePath:.*}")
@Produces({"*"})
public Response getFile(@QueryParam("as_attachment") String asAttachment)
throws IOException, ODKTaskLockException, PermissionDeniedException;
The filePath is relative to the folder holding attachments for the rowId.
@POST
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/attachments/{rowId}/file/
,→{filePath:.*}")
@Consumes({"*"})
public Response putFile(byte[] content)
throws IOException, ODKTaskLockException, PermissionDeniedException,␣
,→ODKDatastoreException;
@POST
@Path("{appId}/tables/{tableId}/ref/{schemaETag}/installationStatus")
@Consumes({"application/json"})
public Response /*OK*/ postInstallationStatus(Object body)
throws AppNameMismatchException,
PermissionDeniedException,
ODKDatastoreException,
ODKTaskLockException;
494 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
This API is used to report the outcome of the synchronization of this table on the client.
In particular, it can be used to determine which devices are up-to-date with respect to the
server’s table contents (i.e., have no conflicts). That information is useful for determining
when rows on the server can be permanently removed after having been marked as deleted.
@POST
@Path("{appId}/installationInfo")
@Consumes({"application/json"})
public Response /*OK*/ postInstallationInfo(Object body)
throws AppNameMismatchException,
PermissionDeniedException,
ODKDatastoreException,
ODKTaskLockException;
This API is invoked after the sync has completed on the client.
This takes a generic JSON object and stores it on the server.
The JSON object (serialization) should be less than 4000 characters in length.
It can be used to determine whether a client successfully synced and provides information
mapping the client’s X-OpenDataKit-Installation-Id back to a physical device (info on the
type of device and the reported Android ID for the device are in the Android implementa-
tion’s object).
Prerequisites
The Android tools, like most Android projects, use Gradle for compilation scripting. Before
reading this document, you should be familiar with Gradle for Android.
Directory Structure
The build scripts for the Android tools expect a particular directory structure. They expect
a parent directory that contains each of them at the same level. This is optional.
If you had all of the Android tools checked out your directory structure would look like this:
/opendatakit/
/androidlibrary/
/androidcommon/
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 495
Chapter 4. Trying It Out
/gradle-config/
/scan/
/sensorsframework/
/sensorsinterface/
/services/
/survey/
/tables/
There are two cases where this directory structure makes a difference:
• Library Projects:
– If androidlibrary and androidcommon are present in the same directory, according
to the above structure, as the Android tools, then they will build against the local
copy. If you want to make changes to Services and androidlibrary simultaneously,
for example, this structure would be necessary.
– If the library projects are not present in the above configuration then a prebuilt
binary will be downloaded according to the flavor you are building. For example,
new binaries are posted on Snapshot for each commit, or on Master for each
release.
• Gradle Config: If the gradle-config project is present in the above configuration,
the gradle files in that folder will be used. Otherwise the release version specifies in
settings.gradle will be used.
The simplest way to build the tools is often to press the build button in Android Studio.
However, the command line can also be used. To invoke the gradle wrapper, enter the root
level of the project to be built and run a command that looks like this:
Note: If you are building with Android Studio, you will need to select the correct build
variant. This is important when you don’t have androidlibrary or androidcommon in your
Directory Structure. These are discussed more in the next section.
Flavors
The Android tools use two dimensions of product flavors. The first dimension determines the
version of the dependencies to pull. Each of the Android tools depends on the androidlibrary
496 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
library project, and some depend on androidcommon as well. Binary versions of these are
posted to Maven and Ivy repositories corresponding to the latest version of each of the three
branches:
• Snapshot is used if you are running the development branch. A new version of the
libraries is automatically posted with each new commit that is merged.
• Demo is used if you are running the demo branch.
• Master is used if you are running the master branch. These are release versions that
have been tested and posted by hand.
Warning: The ODK-X tools prefers pull requests to development. In unusual circum-
stances when development is undergoing heavy change we may accept pull requests to
demo or master depending on the level of incompatibility that might exist.
The other dimension determines whether to apply changes necessary to run the UI tests.
The two options are:
• Basic is used for normal builds
• Uitest is used for builds that will run the UI tests.
Therefore, if you wanted to build the normal version of the master branch, you would run:
./gradlew clean assembleMasterBasic
Running Lint
To run Lint:
./gradlew clean lintSnapshotBasicRelease
Unit Testing
Connected Testing
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 497
Chapter 4. Trying It Out
UI Testing
Note: The previous commands can be run together. For example, to run the two unit test
commands you would run:
This section covers the files that are stored inside each of the Android projects. These paths
follow the same pattern for each Android project, just the project name differs. For clarity,
the root level of the project will be referred to as root and the app/lib level of the project will
be referred to as app. So, for example, the path services/services_app/build.gradle
becomes project/app/build.gradle.
root/settings.gradle
This file determines where to look for the External Build Files.
The gradleConfigVersion corresponds to a tag in the Gradle Config repository. If the
local gradle files are not found, the versions of those files committed under that tag will be
downloaded and used.
Before downloading those files, this file checks the local Directory Structure for gradle-config.
If it is found, that is used. Whichever path is chosen, this linkage is established here and
made available to all the rest of the gradle files.
This file also looks for library projects in the local directory structure. If they are found,
they are built as dependencies. If not, their prebuilt binaries are downloaded.
root/build.gradle
This file establishes URLs to use for resolving dependencies. Links to each of the prebuilt
binary repositories are included (demo, master, snapshot).
498 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.16. Platform Developer Advanced Topics
root/app/build.gradle
The file contains the specific build configuration for this project. The ODK-X projects do not
differ greatly from established norms in this configuration. However, many of the constants
and version numbers are stored in variables.gradle and variables are used here. This allows
the tools to be upgraded and maintained in unison, and they can be forced to stay in sync.
This file also establishes the product flavors, signing configs, build types, and other standard
options found in many Android projects. The unique aspect comes in the dependencies
block. The different flavors have different dependencies (they will download different prebuilt
binaries for their library projects). The demo and snapshot flavors build against the latest
from their repositories, while the master flavor is hard coded to a specific version.
These build files are centralized in the Gradle Config repository. They included shared
configuration, versions, and tasks.
variables.gradle
This file contains all the versions and variables strings shared among the projects. Most
notably this includes the release code version, the compile targets, the Java version, and the
composed project build and variant names.
runnables.gradle
This file contains miscellaneous Gradle tasks necessary to the ODK-X tools. Mostly these
exist to make Jenkins or Artifactory work.
uitests.gradle
This file contains tasks to make the UI tests work on a build server. In particular, they
disable animations and grant external storage permissions.
remote.gradle
This file contains the paths to the remote versions of these files stored on Github or in the
directory structure. This is used by root/settings.gradle to fetch the appropriate files.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 499
Chapter 4. Trying It Out
publish.gradle
This file contains parameters related to the different binary publishing versions the tools use.
jacoco.gradle
This file contains definitions and versions for the Jacoco code coverage tool.
This document explains how to set up your computer and work locally as an ODK Docs
contributor. Local set up includes installing some software, and working locally involves:
• writing documentation text or code in a code editor
• using the Terminal (the ”Shell” or ”Command Line”)
We encourage all potential contributors to try to work locally, following this guide.
Read about the project and the community at Open Data Kit’s website.
Get started with the docs by going to the ODK Docs GitHub README.
Tip: As you are setting up your accounts, keep in mind that it is very helpful (but not
required) to use the same (or similar) username on GitHub, the ODK Developer Slack, and
the ODK Forum.
This makes it easy for other people to keep track of conversations which sometimes span
multiple online platforms.
500 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
If you are willing and able to do so, a profile picture in each place is also very helpful. (But
it is okay if you are unable or uncomfortable adding a picture.)
Tip: The forum has a search feature, and a long history of archived support posts.
When writing new documentation about an existing feature, old forum posts are an
excellent source for figuring out what people need to know: If someone has asked a
question about it, it should probably be in the documentation.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 501
Chapter 4. Trying It Out
It is better to ask a question in the ”wrong” venue than to not ask the question at all. Many
of the same people are present in all three places, and we will help you wherever you happen
to show up.
Initial Setup
502 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Note: We generally recommend starting with the Docker platform for editing docs unless
you already have a Sphinx environment set up. Local tools and workflows presented in this
guide are what the authors feel would be easiest for newcomers and those unfamiliar with
open source.
However, developer and authoring tools have a lot of options and alternatives. You should
feel free to use your preferred tools.
Before you begin working the first time you will need to install a few tools on your computer.
You should only need to do this one time on any computer.
1. Find and open a terminal or command line.
Windows
Mac
Linux
Windows 10
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 503
Chapter 4. Trying It Out
If you’ve never used it before, the Terminal is probably in the Other directory in your
App collection.
Follow the Bash or Mac instructions throughout the contributor guide.
Use a Bash-like shell of your choosing, and follow the Bash or Linux instructions
throughout the contributor guide.
You will also need to be familiar with the relevant package manager for your system.
2. Install git.
Git is a version control system. It helps us keep track of changes to the documentation.
(Similar to the undo history in a document editing program.)
Linux
Mac
Windows
Use your distribution’s package management system to install git on Linux.
504 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 505
Chapter 4. Trying It Out
4. Install Python 3
Python is a programming language.
Most of the ODK Docs tools are written in Python, so you need it installed on your
computer in order to use those tools. (Don’t worry. You don’t need to know how to
program in Python.)
We require Python 3, version 3.6 or later.
Linux
Mac
Windows
Use your distribution’s package management system to install Python 3.6+ on Linux.
(For more help, see Installing Python on Linux.)
Tip: Mac OS includes a legacy (outdated) version of Python. It’s best to just ignore
it.
64-bit or 32-bit?
Python provides 64-bit and 32-bit installers. You probably need the 64-bit in-
staller.
506 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
If you are running a relatively recent Mac OS update (Mountain Lion or later —
any Mac from the last several years) the 64-bit installer is for you.
If you have an older Mac, and are unsure if it can run a 64-bit installer, check the
processor details in � -> About This Mac.
$ python3 --version
Python 3.7.0
The output from python3 --version might be a little different, but it should be
higher than 3.6.
If you get an error here, something went wrong. Try running the installer again.
If the problem persists, and you can’t debug it yourself, asks us about it on ODK
Slack.
The output from python3 --version might be a little different, but it should be
higher than 3.6.
If you get an error here, something went wrong. Try running brew install python
again. If the problem persists, and you can’t debug it yourself, asks us about it on
ODK Slack.
(a) Go to the Python Releases for Windows page.
(b) Under the latest numbered release for Python 3, find and download the Windows
x86-64 web-based installer (for a 64-bit system) or the Windows x86
web-based installer (for a 32-bit system).
64-bit or 32-bit?
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 507
Chapter 4. Trying It Out
Well over 90% of computers running Windows are 64-bit. So you probably need
the 64-bit version.
If you are running a very old or low-powered computer, and you are unsure if
it is 64-bit or 32-bit, you can use this guide from HP (which will work for other
computer brands) to find that information.
The output from python --version might be a little different, but it should be
whatever numbered version you downloaded.
If you get an error here, something went wrong. Try running the installer again.
You may also have to add Python to your Windows search path. You can do
this by going to Advanced System Settings -> Environmental Variables -> Edit
System Variables, then adding the path to the directory containing Python. If
the problem persists, and you can’t debug it yourself, asks us about it on ODK
Slack.
5. Set up your working directory
In whatever directory (folder) on your computer where you organize projects, create a
new directory for Open Data Kit, and then navigate to that directory. (We recommend
calling this directory odk, and the rest of the guide will assume that’s what you called
it.)
Bash
PowerShell
$ mkdir odk
$ cd odk
/odk/ $
For the rest of this guide, we assume you are in the /odk/ directory, or a subdirectory
of it.
508 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
The (odkenv) before the prompt shows that the virtual environment is active.
You will need to have this active any time you are working on the docs.
If the file cannot be found, your activate file may be located under od-
kenv/scripts/activate.
Later, to deactivate the virtual environment:
Bash
PowerShell
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 509
Chapter 4. Trying It Out
On GitHub, a fork is a copy of a repo, cloned from one user to another. In order to
work on ODK Docs, you will create your own fork.
(a) Go to the ODK Docs repo on GitHub.
(b) Use the Fork button (top right) to create your own copy.
(c) After the process completes, you’ll be looking at your own fork on GitHub.
8. Clone down your copy to your local computer
(a) From your own fork of the repo on GitHub, select the Clone or download button.
(b) Copy the URI from the text box that opens. It will be something like: https://
github.com/your-gh-username/docs.git
(c) Use your terminal to clone the repository.
You should already be in the odk directory, with the virtual environment active.
Bash
Powershell
.
.
.
(odkenv) /odk/ $ cd docs
(odkenv) /odk/docs/ $
.
.
.
(odkenv) /odk/ > cd docs
(odkenv) /odk/docs/ >
Note: This will cause your computer to download the entire ODK Docs reposi-
tory, including a large number of images. It will take several minutes to complete.
510 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 511
Chapter 4. Trying It Out
If everything went right, you should see output similar to what is shown above.
10. Install Python tools with pip
Pip is a package management tool that comes with Python. We use it to download and
install our documentation tools. These Python tools are listed in requirements.txt.
Bash
PowerShell
The first command upgrades pip itself to the latest version. Then second checks
requirements.txt and installs everything listed in it. This will take several moments.
Note: If you are ever running one of the build commands shown below and it
fails with a message that includes ModuleNotFoundError, there might be changes to
requirements.txt since you originally ran pip install -r requirement.txt. Run
the installation again and then retry your build.
.. _reStructuredText: http://docutils.sourceforge.net/docs/user/rst/
,→quickref.html
You cannot write and edit these files in a typical document preparation program like
MS Word or Google Docs. Instead, you need a coding editor.
512 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
There are a lot of editors, and people who use them often have very strong opinions
about them. You are free to choose any editor you like.
If you’ve never used an editor before, you might want to start with one of the easier
and more popular ones:
• Atom
• Sublime
• VS Code
• Notebook++ (Windows only)
Most of these have plugins that will make writing reStructuredText easier by color-
coding the markup.
This completes the setup of your local working environment. Take a break before diving into
how you actually work.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 513
Chapter 4. Trying It Out
This will help you get used to working with the documentation tools, and helps us get
rid of the inevitable errors that creep in to our writing.
(b) If you are not on master, switch to master with git checkout.
Bash
PowerShell
514 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Warning: Some git commands (including git pull and git checkout) send
error messages to PowerShell even when they work correctly. If everything seems
to be working, you can ignore these.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 515
Chapter 4. Trying It Out
Branch names should be short, lowercase, and use hyphens as separators. They do not
need to carry a lot of information (like your name or the date).
Good branch names:
• getting-started-guide
• contributing
• fix-issue-13
Bad branch names:
• getting started guide
• Getting started guide
• Getting_started_guide
• writing-the-getting-started-guide-adammichaelwood-july-2017-draft
5. Work on the documentation
Finally, you can open an editor of your choice and work on the documentation.
The source files for documentation text are in these directories:
odk1-src Files for the pages at http://docs.opendatakit.com
odk2-src Files for the pages at http://docs.opendatakit.com/odk2
shared-src Files for pages shared by both ODK1 and ODK2 docs. (This page and
the other contributor guide pages.)
If you’re going to write or edit documentation text, please read:
• Docs Markup and Syntax Guide
• Docs Style Guide
If you’re working on code or deployment, please read:
• Docs Developer Guide
6. Local checks
Once you have worked on the documentation, we want to make sure your contribution
will get accepted and published right away.
To ensure your changes will pass all the deployment tests, you should run the tests
locally first and correct any problems.
(a) Spell check
If you’ve been working on files in odk1-src or shared-src:
Bash
516 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
PowerShell
(odkenv) /odk/docs/ $ make odk1-spell-check
This will send some output to the terminal, which will include mentions of any
words not in the dictionary.
• If the flagged words are really misspellings, correct them.
• If the flagged words are not misspelled, and should be in the dictionary add
them to spelling_wordlist.txt.
• If the flagged words are not misspelled, but should not be in the dictionary
(for example, they are non-words that make sense on a single page for a
specific reason) add them at the top of the file in which they are being used,
before the title heading:
.. spelling::
abc
def
exe
functool
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 517
Chapter 4. Trying It Out
make odk2
This generates a lot of output. Near the end of the output you may see a statement
like:
Those warnings are problems with the text which you need to fix before submitting
your changes. Scroll up in the terminal to find each warning, so that you can address
it in the source files.
518 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
This tells you what file the problem is in, the approximate line number, and the nature
of the problem. Usually that is enough to fix it. If you can not figure out the meaning
of a particular warning, you can always ask about it on the ODK Slack.
Note: Because of a bug in Sphinx the line numbers in error and warning messages
will be off by about 15 lines (the length of rst_prolog in conf.py).
As you fix each warning, run the build again to see if it disappears from the output.
Note: The warning messages will refer to the file name using the temporary directory
path tmp1-src or tmp2-src. You need to correct the problems in the real source
directory (odk1-src, odk2-src, or shared-src).
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 519
Chapter 4. Trying It Out
PowerShell
Note: We explain how to do a commit at this step because you need to do it before
you can submit your changes. However, you don’t have to wait until you are done to
commit. You can commit as many times as you like while working.
This can be especially helpful if you are working on a complicated set of changes, over
several working sessions.
520 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
PowerShell
Tip: You may be prompted to enter your GitHub username and password. When
entering your password, the cursor won’t move — it will look like you aren’t entering
anything, even though you are.
To avoid having to retype these every time, you can store your GitHub credentials
locally.
11. Issue a pull request from your GitHub repo to the main ODK Docs repo.
A pull request (or PR) is a request from you to the ODK Docs maintainers to pull in
your changes to the main repo.
(a) Go to the ODK Docs repo on GitHub. (Make sure you are logged in.)
(b) Find the message near the top of the page that mentions your recent pushed
branches. Select Compare & pull request to start a pull request.
(c) Follow GitHub’s instructions to start the pull request.
These details should fill-in automatically, but be sure to double-check them:
• Base fork should be the main repo (opendatakit/docs).
• base should be master.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 521
Chapter 4. Trying It Out
• Your repo and working branch name should be listed beside them.
You will see either a green Able to be merged message or a message informing
that the branch can not be merged. You can proceed in either case. If the branch
cannot be merged, the maintainers will work with you to resolve the problem.
(d) Write a PR message explaining your work.
The PR message field includes a template to remind you of what to include. Fill
in the template and delete any sections which are not applicable.
A good PR message includes:
• The issue number you are working on. (Write closes #123 if the PR com-
pletes the work for the issue. If there’s still work to do, write addresses
#123.)
• A summary of what you did.
• Details of work that still needs to be done.
• Details of new work created or implied by this PR.
• Details of any unresolved errors or warnings, including details of what you
tried.
• Justification for any changes to requirements.txt.
• Details of any difficulties, questions, or concerns that came up while working
on this issue.
(e) Submit your pull request.
The maintainers and other contributors will review your PR as quickly as possible.
They may request changes to your work. If changes are needed:
(a) Don’t worry. Revision is a normal part of technical writing, and everyone (even
the project’s founders and leaders) has their work reviewed and are frequently
asked to revise it.
(b) Work on the files again locally. (Use git branch to make sure you are still in
the same working branch.)
(c) Stage and commit your changes locally again (git add -A; git commit -m
"Commit message").
(d) Push your commit (git push origin branch-name).
(e) Your new commits will automatically update the PR. Do not start a new PR.
Once everything has been approved, the changes will be merged in and will appear on
this website. At that point… congratulations! You are now a contributor to Open Data
Kit.
522 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
We hope that contributing to ODK Docs is a rewarding experience and that you’ll want
to keep going. Each time you start work on a new issue the process is the same as outline
above.
Here are a few things to keep in mind when you start your next contribution.
1. Return to master with git checkout master.
New work is done on new branches which are started from master. So, before you start
a new branch, return to the master branch.
Bash
PowerShell
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 523
Chapter 4. Trying It Out
Keep improving
As you are getting comfortable with the contribution process, take a few minutes to read
our Tips for Making Good Contributions. You may also want to dig deeper into the Docs
Style Guide and the Docs Markup and Syntax Guide. (And if you are writing code, check
out the Docs Developer Guide.)
And don’t forget to join us on the ODK Slack.
Open Data Kit is a community, and we depend on each other’s work. Thank you for your
contribution to ODK Docs and your presence in this community.
The ODK documentation is built using Sphinx, a static-site generator designed to create
structured, semantic, and internally consistent documentation. Source documents are writ-
ten in reStructuredText, a semantic, extensible markup syntax similar to Markdown.
• reStructuredText Primer — Introduction to reStructuredText
– reStructuredText Quick Reference
– reStructuredText 1-page cheat sheet
• Sphinx Markup — Detailed guide to Sphinx’s markup concepts and reStructuredText
extensions
Note: Sphinx and reStructuredText can be very flexible. For the sake of consistency and
maintainability, this guide is highly opinionated about how documentation source files are
organized and marked up.
Indentation
.. figure:: path-to-image.*
This is the caption of the figure. Notice that it is indented under the line␣
,→defining the figure.
524 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
The exception to the two spaces rule is Ordered (numbered) lists, where indentation follows
the content of the list item.
.
.
.
Documentation Files
Sphinx document files have the .rst extension. File names should be all lowercase and use
hyphens (not underscores or spaces) as word separators.
Normally, the title of the page should be the first line of the file, underlined with equal-signs.
Title of Page
================
You can alternatively wrap the title in two lines of asterisks, in some cases. (This should
not be your default choice.)
*******************
Title of Page
*******************
The asterisks style is useful when you are combining several existing documents and don’t
want to change every subsection headline. Or, you can use it when you are working on
a document that you have reason to think might be split into separate documents in the
future.
Important: If you use the double-asterisks style, your major section headlines (<h2>)
should use the equal-signs underline style. This allows major sections to be easily promoted
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 525
Chapter 4. Trying It Out
to individual pages.
Tables of Content
The toctree directive defines a table of content. The content of a toctree is a list of page
file names, without the .rst extension. When rendered, the toctree becomes an unordered
list of page links, including links to sections and subsections of the included pages.
.. toctree::
page-name
another-page
this-other-page
The depth of section and subsection links to display in the output can be controlled using
the maxdepth attribute. We typically use a depth of 2, but you should use your judgment if
you feel it should be more or less in any given context.
.. toctree::
:maxdepth: 2
this-page
that-page
thick-page
flat-page
See also:
The TOC Tree
The Sphinx documentation includes information about a number of other
toctree attributes.
The index.rst file serves as a front-page to the documentation and contains the main tables
of content, defined using toctree directives.
These toctree directives control the sidebar navigation menu. To add a new document to
a table of content, add the file name (without the .rst extension) to the relevant list of file
names in index.rst.
526 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Collections of documents are sometimes given their own table of content on an individual
page. (See, for example, Setting Up ODK Collect and Using ODK Collect.)
In these cases, the page containing the toctree serves as a sort of intro page for the collection.
That intro must, itself, be included in the Sidebar navigation menu.
The contents of a toctree appear as section links in another toctree it is included in. That
is, if a toctree in index.rst lists collect-using, and collect-using.rst has a toctree,
then the contents of that second toctree will appear in the Sidebar navigation menu, as
sub-items to Using ODK Collect. (Indeed, this is precisely the case in the docs currently.)
Tip: If it not obvious where a new document should appear in the navigation, the best
practice is to simply ask about it in the GitHub issue driving the new page.
Note: For wayfinding purposes, we sometimes create an Unordered (bullet) lists of page
links rather than a toctree directive. (For example, see collect-intro. We do this when
using a toctree would create redundant links in the Sidebar navigation menu.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 527
Chapter 4. Trying It Out
Why are the docs files not grouped into folders in the source?
We use toctree directives as our primary way of organizing the documentation for readers.
We do not organize the source rst files into subfolders.
The reason is that if we put them into topic-related subfolders, it would affect the URI of
the document. Keeping all of our document files in a single flat directory results in a flat
URI structure. Every page’s URI looks like docs.opendatakit.org/page-name.
If we used subdirectories, then our URIs would look like docs.opendatakit.org/
subdirectory-name/page-name. This would mean that our URIs would change every time
we moved a document from one folder to another, greatly increasing the time cost and
broken-link risk of reorganizing the docs.
If you need to combine several existing pages together, or want to start a single-page doc
that you think might be split into individual pages later on, you can add a top-level title,
demoting the other headline types by one.
528 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
************************************************
Page Title - <h1> - Asterisks above and below
************************************************
In either case, the underline of characters needs to be longer than the line of text. In the
case of the asterisks, the two lines of asterisks need to be the same length.
Section labels
In order to facilitate efficient Cross referencing, sections should be labeled. This is done on
the line above the section title. The format is:
• two dots
• underscore
• section label
– lowercase
– hyphen separators
• a single colon
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 529
Chapter 4. Trying It Out
.. _section-label:
Section Title
----------------
ODK Aggregate
===============
.. _aggregate-getting-started:
Getting Started
-----------------
Basic Markup
Escaping characters
*Italic.*
Italic.
*Not italic, surrounded by asterisks.*
530 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Note: The bold, italic, and inline literal styles do not carry semantic meaning. They
should not be used when a more semantically appropriate markup construct is available; for
example, when writing about GUI text.
Hyperlinks
External hyperlinks — that is, links to resources outside the documentation — look like
this:
This is a link to `example <http://example.com>`_.
.. _example: http://example.com
This may help make paragraphs with a lot of links more readable. In general, the inline
style is preferable. If you use the reference style, be sure to keep the link references below
the paragraph where they appear.
You can also simply place an unadorned URI in the text: http://example.com
You can also simply place an unadorned URI in the text: http://example.com
Lists
- use hyphens
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 531
Chapter 4. Trying It Out
- the blank line requirement means that nested list items will have a blank␣
,→line before and after as well
532 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Note: See Ordered and unordered lists in the Docs Style Guide for details on when to use
ordered and unordered lists.
Definition Lists
Terms
should not be indented
Definitions
should be indented under the term
Line spacing
there should be a blank line between term-definition pairs
Paragraph-level Markup
Paragraphs are separated by blank lines. Line breaks in the source code do not␣
,→create line breaks in the output.
There is **no reason** to put a limit on line length in source files for␣
,→documentation, since this is prose and not code. Therefore, please do not put␣
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 533
Chapter 4. Trying It Out
Paragraphs are separated by blank lines. Line breaks in the source code do not create line
breaks in the output.
This means that you could, in theory, include a lot of arbitrary line breaks in your source
document files. These line breaks would not appear in the output. Some people like to do
this because they have been trained to not exceed 80 column lines, and they like to write
.txt files this way. Please do not do this.
There is no reason to put a limit on line length in source files for documentation, since this
is prose and not code. Therefore, please do not put arbitrary line breaks in your files.
Block Quotes
This is not a block quote. Block quotes are indented, and otherwise unadorned.
This is not a block quote. Block quotes are indented, and otherwise unadorned.
This is a block quote. — Adam Michael Wood
Line Blocks
534 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Tables
Grid style
+------------+------------+-----------+
| Header 1 | Header 2 | Header 3 |
+============+============+===========+
| body row 1 | column 2 | column 3 |
+------------+------------+-----------+
| body row 2 | Cells may span columns.|
+------------+------------+-----------+
| body row 3 | Cells may | - Cells |
+------------+ span rows. | - contain |
| body row 4 | | - blocks. |
+------------+------------+-----------+
Simple style
Inputs Output
A B A or B
False False False
True False True
False True True
True True True
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 535
Chapter 4. Trying It Out
CSV Table
The csv-table role is used to create a table from CSV (comma-separated values) data. CSV
is a common data format generated by spreadsheet applications and commercial databases.
The data may be internal (an integral part of the document) or external (a separate file).
536 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
:widths: auto
:delim: #
"Peter"#"A"
"Paul"#"B"
"Peter"|"A"
"Paul"|"B"
:align:
It specifies the horizontal alignment of the table. It can be left, right or center.
"Peter", "A"
"Paul", "B"
:file:
Contains the local file system path to a CSV data file.
:url:
Contains an Internet URL reference to a CSV data file.
Note:
• There is no support for checking that the number of columns in each row is the same.
However, this directive supports CSV generators that do not insert ”empty” entries at
the end of short rows, by automatically adding empty entries.
"Peter"
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 537
Chapter 4. Trying It Out
"Paul", "B"
Note: In almost all cases, csv-table is the easiest and most maintainable way to insert a
table into a document. It should be preferred unless there is a compelling reason to use one
of the other styles.
Sphinx-specific Markup
A role is an inline markup construct that wraps some text, similar to an HTML or XML
tag. They look like this:
:rolename:`some text`
Most of the Sphinx-specific and ODK-specific markup will use one or both of these constructs.
Cross referencing
Cross referencing is linking internally, from one place in the documentation to another. This
is not done using the Hyperlinks syntax, but with one of the several roles:
538 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
:role:`target`
becomes...
<a href="target">reference title</a>
:doc:
• Links to documents (pages)
• target is the file name, without the .rst extension
• title is the first headline ( <h1> ) of the page
:ref:
• Links to sections
• target is the Section labels
• title is the section title (headline)
:term:
• Links to items in the Glossary
• target is the term, in the glossary
• title is the term itself
To recap: If you do not include an explicit target, the text inside the role will be understood
as the target, and the anchor text for the link in the output will be the title of the target.
For example:
- :doc:`contributing`
- :doc:`anchor text <contributing>`
- :ref:`cross-referencing`
- :ref:`anchor text <cross-referencing>`
- Link to a term:
- :term:`participant`
- :term:`anchor text <participant>`
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 539
Chapter 4. Trying It Out
:menuselection:
Marks up the actual UI text of a navigation menu or form select element.
When writing about multi-level menus, use a single :menuselection: role, and sepa-
rate menu choices with -->.
Note: In some situations you might not be clear about which option (menuselection or
guilabel) to use. GUIs in real life can sometimes be ambiguous. The general rule is:
• Actual UI text will always receive guilabel role unless the text could reasonably be
understood to be part of a menu.
• If the actual UI text could be understood as a menu, menuselection should be used.
These both render the same on output, so don’t worry too much if you get it wrong. Just
use your judgment and take your best guess.
540 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
:kbd:
Marks up a sequence of literal keyboard strokes.
:command:
Marks up a terminal command.
:option:
Marks up a terminal command option.
:gesture:
Describes a touch screen gesture.
:gesture:`Swipe Left`
We have added several custom text roles for writing about forms and the XForms and
XLSForm formats.
:th:
Used to refer to a table header cell.
:tc:
Used to refer to a table cell.
:formstate:
Specifies the state of the form in ODK Collect, which could be one of the following:
• Blank
• Finalized
• Saved
• Sent
• Deleted
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 541
Chapter 4. Trying It Out
:formstate:`Sent`
:abbr:
Marks up an abbreviation. If the role content contains a parenthesized explanation, it
will be treated specially: it will be shown in a tool-tip in HTML.
:dfn:
Marks the defining instance of a term outside the glossary.
:dfn:`Open Data Kit` (ODK) is a suite of open source applications that help␣
,→organizations engaged in enumerator-mediated data collection.
:file:
Marks the name of a file or directory. Within the contents, you can use curly braces
to indicate a ”variable” part.
is installed in :file:`/usr/lib/python2.{x}/site-packages`
PNGs only
All still images used in ODK Docs should be PNG files. This helps us keep our image
compression tooling simple, and generally results in higher-quality screenshots.
Whenever possible, you should generate your images as PNGs rather than converting to
PNGs from another format. If you have to start in another format, use lossless formats
whenever possible. These include BMP, GIF, and TIFF. (Avoid JPG/JPEG if possible, as
this is a lossy format that does not replicate screenshots very well.)
542 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Image files should be put in the /src/img/ directory in the source, and they should be in
a subdirectory with the same name as the document in which they appear. (That is, the
filename without the .rst extension.)
Image compression
Before committing images locally, run lossless compression on them using one of the following
tools:
• ImageOptim
• Pngout
.. image:: /img/{document-subdirectory}/{file}.*
:alt: Alt text. Every image should have descriptive alt text.
Note the literal asterisk (*) at the end, in place of a file extension. Use the asterisk, and
omit the file extension.
.. figure:: /img/{document-subdirectory}/{file}.*
:alt: Alt text. Every image should have descriptive alt text.
The rest of the indented content will be the caption. This can be a short␣
,→sentence or several paragraphs. Captions can contain any other rst markup.
Inline images
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 543
Chapter 4. Trying It Out
544 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
If you have set up Android Debug Bridge, you can connect your Android device to your
computer and take screenshots from the command line.
• Connect your device via USB
• Enable Developer Settings
– Settings → About phone
– Tap Build number seven (7) times
• Turn on USB Debugging
– Settings → Developer options → USB debugging
Now, at the command line, from the root directory of the odk-docs repo:
• {document-name} is the filename (without extension) where the image will be used.
• {image-name} is the name (without extension) given to the image. - follow the Image
File Names guidelines
Tip: If you have a problem running ss.py, check to make sure your Python 3 virtual
environment is activated.
Tip: Be sure to obscure any personally-identifiable information from screen shots. Crop to
the smallest relevant screen area. Annotate screen shots with arrows or circles to indicate
relevant information.
Videos
Video files should be put in the /src/vid/ directory in the source, and they should be in
a subdirectory with the same name as the document in which they appear. (That is, the
filename without the .rst extension.)
The purpose of on page videos is to illustrate complicated user interactions that might be
difficult to describe otherwise. Longer tutorial videos should be hosted elsewhere and, if
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 545
Chapter 4. Trying It Out
.. video:: /vid/{document-subdirectory}/{file}.ext
Note: Images to be used as poster for a video should be in the same directory as
the video and should have a filename like [same-file-name-as-video]-poster.
ext.
546 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
:class:
Specifies a class for the video element.
For more details on these attributes, see this guide.
To add a video in a document with the above options, you can do the following:
.. video:: /vid/{document-subdirectory}/{file}.ext
:autoplay: yes/no
:controls: yes/no
:muted: yes/no
:loop: yes/no
:class: class-name
:preload: auto/metadata/none
:poster:: /vid/{document-subdirectory}/{file}.ext
Android Debug Bridge (ADB) can be used to capture a screen recording from an Android
app.
On pressing the enter key the video recording starts. Recording stops automatically after 3
minutes. Since videos have to be less than a minute, press CTRL C to stop the recording.
The video file is saved in your Android device to a file at /sdcard/example.mp4 file.
To pull the video locally:
Downloadable files
Downloadable files should be put in the /src/downloads/ directory in the source, and they
should be in a subdirectory with the same name as the document in which they appear.
(That is, the filename without the .rst extension.)
To place a downloadable file in a document, use the download role.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 547
Chapter 4. Trying It Out
Code Samples
Use the code-block directive to insert code samples. Specify the language on the same line
as the directive for syntax highlighting.
.. code-block:: rst
.. code-block:: python
print("Hello ODK!")
.. code-block:: console
$ python --version
.. code-block:: java
Note: rst code-blocks wrap overflow lines by default. To unwrap overflow lines, use
unwrap class with rst code-blocks.
.. code-block:: rst
:class: unwrap
Code-blocks for other languages don’t wrap overflow lines. Instead of wrapping, you need to
scroll side-ways. To wrap overflow lines with other code-blocks, use wrap class with them.
.. code-block:: python
:class: wrap
Substitutions
Substitutions are a useful way to define a value which is needed in many places.
548 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Substitution definitions are indicated by an explicit markup start (”.. ”) followed by a vertical
bar, the substitution text (which gets substituted), another vertical bar, whitespace, and the
definition block.
A substitution definition block may contain inline-compatible directives such as image or
replace. For more information, refer this guide.
You can define the value once like this:
You can use the hyperlink reference by appending a ”_” at the end of the vertical bars, for
example:
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 549
Chapter 4. Trying It Out
Whenever U.S. English and British (or other) English spelling or usage disagree, standard
U.S. spelling and usage is preferred.
Wrong
Right
550 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
@memoize
def check_ukus(text):
"""UK vs. US spelling usage."""
err = "style-guide.uk-us"
msg = "uk-vs-us-spell-check. '{}' is the preferred spelling."
preferences = [
["gray", ["grey"]],
["color", ["colour"]],
["accessorizing", ["accessorising"]],
["acclimatization", ["acclimatisation"]],
["acclimatize", ["acclimatise"]],
["acclimatized", ["acclimatised"]],
]
# This is a sample code. The complete code can be found in the file:
# proselint-extra.py.
Quote marks
Quote marks are used in prose writing to indicate verbatim text. This is rarely useful in
technical writing, as verbatim text usually requires a more specific semantic markup.
Wrong
Right
Click :guilabel:`Save`.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 551
Chapter 4. Trying It Out
Wrong
You may see an error message that says, "Something went wrong."
Right
def check_quotes(text):
"""Avoid using straight quotes."""
err = "style-guide.check-quote"
msg = "Avoid using quote marks."
regex = r"\"[a-zA-z0-9 ]{1,15}\""
errors = []
return errors
Straight quotes
Any time that you do need to use quotation marks, use straight (or plain) quotes. Sphinx
and Docutils will output the typographically correct quote style.
def check_curlyquotes(text):
"""Do not use curly quotes."""
err = "style-guide.check-curlyquote"
msg = "Do not use curly quotes. If needed use straight quotes."
regex = r"\“[a-zA-z0-9 ]{1,15}\”"
errors = []
552 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
extent = matchobj.end()-matchobj.start()
errors += [(err, msg, row, col, start, end,
extent, "warning", "None")]
return errors
Serial comma
Wrong
Right
@memoize
def check_comma(text):
"""Use serial comma after penultimate item."""
err = "style-guide.serial-comma"
msg = "Use serial comma after penultimate item."
regex = "\,\s[a-zA-Z0-9]+\sand\s"
Correct
Possibly Better
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 553
Chapter 4. Trying It Out
- git
- GitHub
- Python
There’s no hard rule about which to use in any situation. Use your judgement: try it both
ways and see which is more clear.
Direct Address
Direct address — speaking directly to the reader using the second person ”you” — is pre-
ferred over passive voice (”it can be done”), first-person plural (”we can do it”), or other
constructions.
First person plural (”we”) should only be used when speaking of the ODK project team
(”We recommend…”).
An ordered list is numbered. It should be used when the order of the list is essential. For
example, when enumerating a series of steps in a procedure.
Wrong
- First we do this.
- And then we do this.
- And then we do this.
Right
1. Do this.
2. Do this.
3. Do this.
An unordered list is bulleted. It should be used for a collection of items in which order is
not essential.
554 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Wrong
1. apples
2. oranges
3. bananas
Right
- apples
- oranges
- bananas
Avoid Latin
Wrong
Right
If you are writing about a specific process (for example, installing an␣
,→application)...
@memoize
def check_latin(text):
"""Avoid using Latin abbreviations."""
err = "style-guide.latin-abbr"
msg = "Avoid using Latin abbreviations like \"etc.\", \"i.e.\"."
list = [
"etc\.", "etc", "\*etc\.\*", "\*etc\*",
"i\.e\.", "ie", "\*ie\.\*", "\*ie\*",
"e\.g\.", "eg", "\*eg\.\*", "\*eg\*",
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 555
Chapter 4. Trying It Out
Etc.
Adverbs
Wrong
556 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Right
Wrong
Right
@memoize
def check_adverb(text):
"""Avoid using unneeded adverbs."""
err = "style-guide.unneed-adverb"
msg = "Avoid using unneeded adverbs like \"just\", \"simply\"."
list = [
"simply",
"easily",
"just",
"very",
"really",
"basically",
"extremely",
"actually",
]
Many words and phrases provide no direct meaning. They are often inserted to make a
sentence seem more formal, or to simulate a perceived style of business communication.
These should be removed.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 557
Chapter 4. Trying It Out
@memoize
def check_filler(text):
"""Avoid using filler phrases."""
err = "style-guide.filler-phrase"
msg = "Avoid using filler phrases like \"to the extent that\"."
list = [
"to the extent that",
"when all is said and done",
"from the perspective of",
"point in time",
]
Semicolons
Semicolons are used to separate two independent clauses which could stand as individual
sentences but which the writer feels would benefit by close proximity.
Semicolons can almost always be replaced with periods (full stops). This rarely diminishes
correctness and often improves readability.
Correct
These "canned phrases" are pervasive in technical writing; remove them whenever␣
,→they occur.
558 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Better
These "canned phrases" are pervasive in technical writing. Remove them whenever␣
,→they occur.
@memoize
def check_semicolon(text):
"""Avoid using semicolon."""
err = "style-guide.check-semicolon"
msg = "Avoid using semicolon."
regex = ";"
Pronouns
Wrong
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 559
Chapter 4. Trying It Out
Right
Correct
When using Collect, first the enumerator opens the app on their device. Then␣
,→they complete the survey.
Better
To use Collect:
@memoize
def check_pronoun(text):
"""Avoid using third-person personal pronouns."""
err = "style-guide.personal-pronoun"
msg = "Avoid using third-person personal pronouns like \"he\", \"she\". In␣
,→case of absolute need, prefer using \"they\"."
list = [
"he",
"him",
"his",
"she",
"her",
"hers",
]
560 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
”Same”
Wrong
Right
Right
@memoize
def check_same(text):
"""Avoid using impersonal pronoun same."""
err = "style-guide.check-same"
msg = "Avoid using \"The same\"."
regex = "\. The same"
Titles
Document titles should be in Title Case – that is, all meaningful words are to be capitalized.
Section titles should use Sentence case – that is, only the first word should be capitalized,
along with any proper nouns or other words usually capitalized in a sentence.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 561
Chapter 4. Trying It Out
Verb forms
If a document or section describes a procedure that someone might do, use a verb ending in
-ing. (That is, a gerund.) Do not use the ”How to…” construction.
Wrong
Right
@memoize
def check_howto(text):
"""Avoid using how to construct."""
err = "style-guide.check-howto"
msg = "Avoid using \"How to\" construction."
regex = "(How to.*)(\n)([=~\-\"\*]+)"
Section labels
562 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
def check_label(text):
"""Prefer giving a section label."""
err = "style-guide.check-label"
msg = "Add a section label if required."
regex = r"(.*\n)(( )*\n)(.+\n)(([=\-~\"\']){3,})"
errors = []
sym_list = ['===','---','~~~','"""','\'\'\'']
is_doc_title = True
return errors
ODK Documentation includes code samples in a number of languages. Make sure to follow
generally accepted coding style for each language.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 563
Chapter 4. Trying It Out
Indenting
In code samples:
• Use spaces, not tabs.
• Two spaces for logical indents in most languages.
– Python samples must use four spaces per indent level.
• Strive for clarity. Sometimes nonstandard indentation, especially when combined with
non-syntactic line breaks, makes things easier to read.
– Make sure that line breaks and indentation stay within the valid syntax of the
language.
Using two spaces keeps code sample lines shorter, which makes them easier to view.
Meaningful names
Wrong
def myFunction(foo):
return foobar
564 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Some of the terms often used to describe XML and HTML code structures are imprecise or
confusing. For clarity, we restrict certain terms and uses.
Likewise, coding practices and styles for XML and HTML vary widely. For the sake of clarity
and consistency, samples should follow the guidelines set forth here.
Element
<element>
Some content.
</element>
Tag
The word tag has often been used to refer to the entire element. For clarity, we will avoid
that here.
Node
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 565
Chapter 4. Trying It Out
An element may have attributes. Attributes have values. Values are wrapped in straight
double-quotes.
<element attribute="value">
Content.
</element>
Element content
The code between the opening and closing tags of an element is the content. Content can
include other elements, which are called child elements.
<element>
Content.
<child-element>
More content.
</child-element>
</element>
In XML, null element tags always self-close. This is not the case in HTML.
• HTML elements that are always null (for example, <img>) do not need to be self-
closed.
• Empty HTML elements that normally accept content have a separate closing tag.
<img src="awesome-picture.jpeg">
<script src="some-javascript.js"></script>
Capitalization
For all HTML samples, tag names and attribute names should be all lowercase.
566 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
ODK jargon
Wrong
• Odk
• odk
• Open data kit
• OpenDataKit
• the Open Data Kit
• ODK docs
• ODK documentation
Right
• ODK
• Open Data Kit
• ODK Docs
• ODK Documentation
@memoize
def check_odkspell(text):
"""ODK spelling usage."""
err = "style-guide.spelling-odk"
msg = "ODK spell check. '{}' is the preferred usage."
preferences = [
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 567
Chapter 4. Trying It Out
@memoize
def check_appspell(text):
"""ODK spelling usage."""
err = "style-guide.spelling-odk"
msg = "ODK spell check. '{}' is the preferred usage."
preferences = [
["Aggregate", ["{0} aggregate"]],
["Briefcase", ["{0} briefcase"]]
]
568 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Wrong
• Xforms
• X-Forms
• xforms
• XFORMS
• XForm (no s, when referring to the specification)
• xlsform
• XLSform
• Xlsform
Right
• XForms
• an Xform (when referring to a single form)
• XLSForm
@memoize
def check_formspell(text):
"""ODK spelling usage."""
err = "style-guide.spelling-odk"
msg = "ODK spell check. '{}' is the preferred usage."
preferences = [
["XForms", ["Xforms"]],
["XForms", ["X-Forms"]],
["XForms", ["{0} xforms"]],
["XForms", ["XFORMS"]],
["an XForm", ["a XForm"]],
["an XLSForm", ["a XLSForm"]],
["XLSForm", ["{0} xlsform"]],
["XLSForm", ["XLSform"]],
["XLSForm", ["Xlsform"]]
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 569
Chapter 4. Trying It Out
XLSForm
This document is for contributors working on the design, templating, deployment, or devel-
opment of the ODK Docs website.
Tech Overview
570 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Custom JavaScript
Custom CSS
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 571
Chapter 4. Trying It Out
div[class^='example'] {
color: black;
}
It is helpful to keep the CSS file organized. There are several sections in the custom.css
file:
• Styling for rst roles and directives
• Responsive CSS
• Styling for JS implementation
• Utility classes
Each of these sections are enclosed in start and end comments. Add your code to the relevant
section. If you don’t find any section relevant, add a new section and add your code there.
For example:
div[class^='example'] {
color: black;
}
Proselint is used for style testing the docs. Apart from the built-in tests in proselint, custom
checks are added for style guide testing. Following a literate programming. model, style
checks are defined in docs-style-guide.rst. After each style rule, you can define a python
code-block containing the code for style testing. When the style-test script is run, these
python code-blocks are parsed to generate a testing script.
In most of the custom checks, a new function is written that calls one of the built-in proselint
functions as a return value.
All the checks use a decorator memoize() to cache the check for faster execution.
572 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
memoize()
Use @memoize above function definition to cache the result.
Proselint provides several functions for defining style tests:
existence_check(text, list, err, msg, ignore_case=True, str=False,
max_errors=float(”inf”), offset=0, require_padding=True,
dotall=False, excluded_topics=None, join=False)
To check for existence of a regex pattern(s) in the text. The parameters offset,
excluded_topics and join are not needed for style guide testing.
Parameters
• text (str) – Text to be checked
• list (list) – List of regex expressions
• err (str) – Name of the test
• msg (str) – Error or warning message
• ignore_case (bool) – For using re.IGNORECASE
• str (bool) – For using re.UNICODE
• max_errors (float) – Maximum number of errors to be generated
• require_padding (bool) – To use padding with the specified regex
(It is better to set it as False and specify the regex accordingly)
• dotall (bool) – For using re.DOTALL
Returns The error list consisting of error tuples: [(start, end, err,
msg, replacement)].
Return type list
preferred_forms_check(text, list, err, msg, ignore_case=True, offset=0,
max_errors=float(”inf”))
To suggest a preferred form of the word used. The parameter offset is not needed
for style guide testing.
Parameters
• text (str) – Text to be checked
• list (list) – list of comparison (words or regex): [correct form
, incorrect form]
• err (str) – Name of the test
• msg (str) – Error or warning message
• ignore_case (bool) – For using re.IGNORECASE
• max_errors (float) – Maximum number of errors to be generated
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 573
Chapter 4. Trying It Out
Returns The error list consisting of error tuples: [(start, end, err,
msg, replacement)].
Return type list
consistency_check(text, word_pairs, err, msg, offset=0)
To check for consistency for the given word pairs. The parameters offset is not needed
for style guide testing.
Parameters
• text (str) – Text to be checked
• word_pairs (list) – Word pairs to be checked for consistency
• err (str) – Name of the test
• msg (str) – Error or warning message
Returns The error list consisting of error tuples: [(start, end, err,
msg, replacement)].
Return type list
Note: The checker functions are used by the built-in proselint function lint() to generate
an error list of different format. The returned list finally is: [(check, message, line,
column, start, end, end - start, "warning", replacements)]
See also:
Proselint source code
Example Usage
@memoize
def example(text):
"""Example check."""
err = "style-guide.example"
msg = "A demonstration for writing checks."
regex = "[\.\?!](example)"
When you define code-blocks which use built-in proselint testing, specify the class style-
checks.
574 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
.. code-block:: python
:class: style-checks
The generated file after parsing code for style checks is style-checks.py.
If the test is too large to be defined in the file docs-style-guide.rst, you can use
a snippet from the test (as here). The code-blocks for such snippets should specify
the class proselint-extra-checks. Define the complete test in the file /style-guide/
proselint-extra-checks.py.
Independent checks
Apart from the checks, which are to be run through proselint, you can add extra checks
to be run independently. They are not enabled in proselintrc as well. For example, the
checks for finding quote marks and section labels do not use any built-in functions to obtain
an error list.
Example Usage
def check_quotes(text):
"""Avoid using straight quotes."""
err = "style-guide.check-quote"
msg = "Avoid using quote marks."
regex = r"\"[a-zA-z0-9 ]{1,15}\""
errors = []
return errors
The code-blocks for extra checks should specify the class extra-checks. The generated file
after parsing code for extra checks is extra-checks.py.
Note: Built-in proselint function line_and_column() is used with extra checks to obtain
the row and column of the matched text.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 575
Chapter 4. Trying It Out
line_and_column(text, start)
To find the line number and column of a position in a string.
Parameters
• text (str) – Text to be searched for
• start (int) – Starting position of matched pattern
Returns Tuple containing row and column number
Return type tuple
Error vs warning
To exclude an built-in proselint check, specify the check name in the check list in the function
exclude_checks() in the file style-test.py.
Smallest meaningful PR
A PR should normally address one issue. This makes it easier to review, easier to deploy,
and easier to roll back in case of a problem. Additionally, the smaller the PR, the less likely
it is to create a merge issue.
The exception is when several issues are closely related or can reasonably be worked on
together. In this case, it should be clear by looking at the conversation on the Github issues
that the items are related and will be worked on together. Your PR message should also
576 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
make it clear which issues are being worked on, and whether the PR closes the issues or not.
Mention the PR by number:
addresses #123
closes #123
Descriptive PR names
A PR title should answer the question, ”What does this Pull Request do?”
Good PR titles:
• adds a video directive
• makes navigation buttons responsive
• swaps placement of nav buttons and file an issue note
Bad PR titles:
• fix issue
• fix #123
• collect
When working locally, commit often. Don’t wait until you have 100 lines of changes across
multiple files.
• If you need to copy or move a large section or file, commit that change before also
editing it.
• If you have to create a new template file based on an existing template file, copy the
file in one commit and then work on the changes. This makes it easier to know what
you actually did.
• If writing a new doc, commits after each new section are a good idea.
Commit messages should answer the question, ”What does this commit do?”
Small, well-named commits will help you keep track of your own work and make rollbacks
and other changes easier to deal with.
Take the time to clarify the needs and scope of an issue before committing to work on it.
Especially for coding tasks, make sure you state your understanding and your plan before
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 577
Chapter 4. Trying It Out
working.
If you have a question, ask. Don’t guess.
Note: Many new contributors don’t ask questions because they are worried about appearing
under informed. Please set this worry aside.
You will never be judged harshly for asking clarifying questions or for seeking
more information.
Claim issues
If you decide to work on an issue, let the community know you are working on it by claiming
the issue.
@opendatakit-bot claim
Once you’ve claimed an issue, other people won’t work on it. So make sure you’re actually
going to work on it before claiming it.
Don’t claim more than one or two open issues at a time.
It can be helpful to share your in-progress work. To mark a PR as a work in progress, append
WIP: to the beginning of the PR title. We will not merge WIP PRs, and we won’t do a
review on them unless you ask.
If you want a review, comment, opinion, or help on a WIP PR, please tag the relevant
person in the PR comments.
If you finish the work and want the PR to be merged, you do not need to open a new one.
Just edit the PR title.
• Ask for help in the issue comments. Maybe you can get back on track and complete
the issue.
– Asking questions is always better than guessing.
• Submit a WIP (work in progress) pull request.
– If we can see what progress you have made, it is easier to offer help.
– Even if you don’t complete the task, perhaps someone else can pull in your in-
progress work and build on it.
578 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
– Sometimes your in-progress work is an improvement over not having it, and so
we’ll merge in something even if it isn’t complete.
• If you really cannot move forward, it is okay to abandon an issue.
Sometimes you simply cannot complete work you have said you were going to complete.
This could happen because you don’t have all the required skills or knowledge to complete
the work, or because the issue cannot actually be completed as scoped, or because you don’t
have the time.
Please let the community know in the issue discussion.
@opendatakit-bot unclaim
This way, everyone knows that someone else can take up the project (or that we need to
rethink it).
If you did significant work on a project before abandoning it, consider filing a WIP (work
in progress) PR, so that others can see what you did and potentially build off of it. (Be sure
to mention the issue, so the work is easy to find later.)
For our purposes, a ”long time” is a week or more, from when you first announce your
intention to work on something until submitting a merge-ready PR.
An issue might take a long time because:
• it is complex and requires lots of hours
• you only have a short period of time each day to work on it
• you are new to the project and are having to learn as you go
The thing that matters is: Are you actively working on the issue, and making
progress, at least a little bit?
If you are actively working on it, we do not want someone else to jump on and try to work
on it at the same time. So please keep the community informed of your work by filing a
WIP (work in progress) PR and committing to it as you work.
Issues only
All PRs must be directly connected to open issues. PRs should not represent suggestions,
good ideas, or independent initiative.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 579
Chapter 4. Trying It Out
If you have a good idea, file an issue. If you are curious about whether something should be
an issue, chat with one of the core team in the #docs-code channel on the Slack.
Once you have filed an issue, wait for comment and approval before diving into the work.
We do not want surprise PRs.
You cannot write effectively about tools you have not used. If you’re going to write or edit
documentation about any of the apps in the ODK ecosystem, you need to spend some time
actually using it.
Before diving into writing documentation, try out the core tools here
https://opendatakit.org/software and become familiar with them.
This is also true of writing about Sphinx or any of our documentation build tools. Reading
existing documentation is not enough to write about something.
If you are writing about a specific process (installing an application, for example), you need
to actually complete the process yourself. If possible, follow your own instructions after
writing them to make sure they make sense.
Before submitting a PR, run the build locally to make sure you do not produce any errors
or warnings. We do not accept PRs that produce errors or warnings.
It is best to run the build frequently as you work. You’ll often catch simple mistakes that
are harder to track down later.
Impostor syndrome is the feeling that you are not good enough or accomplished enough to
do the work you are doing.
We all feel this way sometimes, and that’s okay. But it is important to realize that you are
not an impostor.
You can contribute to this community, no matter your background or skills.
• If there is something you don’t know how to do, you can ask.
– If it is issue related, ask on the issue.
580 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
– If it is more general, try the #docs-code channel in the ODK Developer Slack.
• If you want to try something even though you aren’t sure you can do it, go ahead and
try.
Another worry you may have is that something will take you a long time when an ”expert”
might be able to do it quickly. You may feel, then, you aren’t the ”right person” for the
job. But if you are the only one with the time or desire to work on something, you are the
right person to work on it.
The main contribution guide :doc: contributing was built for *nix systems, and the same
commands may not work in Windows. Cygwin is a Windows tool, equivalent to *nix bash
terminal. This guide helps to set up ODK Docs platform from the default Windows command
prompt (CMD).
The prerequisites
The following are software tools that you need in the first place. If it is already installed.
Just follow the steps and apply what is missing.
• Cygwin
• Python 3
• Virtualenv
• Virtualenvwrapper-win
• Git and GLFS
The requirements
These are a set of the main packages. ODK team combined them in a file such that all will
be installed at once.
• alabaster==0.7.10
• Babel==2.4.0
• docutils==0.13.1
• imagesize==0.7.1
• Jinja2==2.9.6
• MarkupSafe==1.0
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 581
Chapter 4. Trying It Out
• Pygments==2.2.0
• pytz==2017.2
• requests==2.14.2
• six==1.10.0
• snowballstemmer==1.2.1
• Sphinx==1.6.1
• sphinx-rtd-theme==0.2.4
• sphinxcontrib-websupport==1.0.1
• typing==3.6.1
• update==0.4.4
Install Cygwin
Cygwin tool lets Windows users execute many *nix commands. Install Cygwin and add its
path to Windows to work completely from the default command prompt. For instructions.
Warning: If you encounter any downloading problems, make sure to select a mirror
site near you. The entire list is available on the Cygwin website.
Python 3
You need to install Python 3. Select Python installation that fits your system (32 or 64 bit).
For instructions, see.
Make sure to select the option ”Add Python to the Path”, as shown below.
582 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
Alternatively, if you forgot to add Python 3 to the PATH, add it manually using the following
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 583
Chapter 4. Trying It Out
command:
Virtual Environment
A virtual environment tool creates multiple Pythons environments, each has its packages
and dependencies.
For easy installation, pip command can be used, which comes with Python 3 (as shown in
Python installation).
Create a new Python 3 virtual environment, ”odkenv” is the name of the virtualenv, you
can choose any name.
After creating the virtualenv, multiple files are copied into the folder odkenv in your working
directory.
> ls odkenv
584 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.
4.17. Contributing to ODK Docs
> cd odkenv
.
.
.
> cd Scripts
> odk/odkenv/Scripts/activate.bat
> odk/odkenv/Scripts/deactivate.bat
Tip: This step is not an alternative to virtualenv. You must install virtualenv first.
(odkenv) /odk/docs
> deactivate
• Install Git for windows. Make sure that git is installed properly by typing (git) in the
CMD.
Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2. 585
Chapter 4. Trying It Out
• Install GLFS.
Android Tools
Install Android Debug Bridge <collect-adb> to learn more about ADB. ADB is part of
Android studio, To download
To use ADB, you must run Android Studio once. The default location of ADB is C:/Users/
your username/AppData/Local/Android/sdk/platform-tools. Add it to Windows PATH
by using the following command:
From Github, fork the ODK Docs. This will create a copy of the docs in your Github account
called origin. Move to the ODk working directory, and clone the ODk Docs into your local
machine.
This step will install a bunch of packages that are listed in the :file: requirement.txt file.
ODK team prepared this file for you to ease the installation.
First, you need to activate your virtual environment (odkenv):
Make sure you are inside the docs folder, then run:
You completed the installation and you can start change and build ODK Docs.
586 Our documentation is updated frequently. Get the latest version at https://docs.opendatakit.org/odk2.