Referencing the Location/Organization Hierarchy in Applications
Please note the documentation below requires more technical expertise
The documentation below may require knowledge of more technical software management and development topics.
This page discusses how to reference the location hierarchy in various parts of apps.
Enabling Access to Location Hierarchy
All new projects have the location hierarchy.
Some older projects may be setup to only receive the Old Hierarchical Fixture. To transition to the flat fixture, go to project settings, then choose Pre-Release Features -> Location Fixture. You can use this to turn on the new location format (flat fixture). Once you have done this, new versions of the app will start to use the new location format. Once all your existing users have transitioned to a new version of the application that uses the new location format, turn off the hierachical fixture. This process is described in depth at https://dimagi.atlassian.net/wiki/x/cinKfw.
The User's location
To pull the current user's location ID you can use the "commcare_location_id" session variable. To reference this in a form, use the following expression:
instance('commcaresession')/session/user/data/commcare_location_id
The Location Hierarchy
To reference the location hierarchy in forms you need edit the source XML by hand and construct complicated xpath expressions.
Ensure that the Locations Data Source is Available
First, you'll need to make sure that the form has a reference to the Locations data source.
The easiest way to accomplish this is to ensure that your question has at least one select question with locations as choices.
If your form doesn't contain one of those questions you can create a 'dummy' question:
Below you'll see instructions for "Making select questions with locations as choices"
Follow those instructions to add a locations lookup to the form
Set the Display Condition for that question to false()
After those steps you should be able to reference locations elsewhere in the form.
Note: If you are using a Locations driven select question in the form, you won't need to keep around the 'dummy' question as well.
Referencing the properties of the user's location (or location ancestor) in a form
You can use the following templates to reference the properties of the user's location (or ancestors). These examples assume a hierarchy of state --> district --> block --> outlet. These expressions will need to be customized to your own hierarchy. To find the code to use for each organization level, on the Organization Level page, click on the Advanced checkbox.
For example, if my location hierarchy has village → city → county→ and I'm trying to pull the city's ID for my current village user, I would take this example from below:
instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@block_id
and modify @block_id to say @city_id
instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@city_id
I am a... | referencing my... | syntax in forms |
outlet | own location's name | instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/name |
outlet | own location's type | instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@type |
outlet | own location's site code | instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/site_code |
outlet | own location's custom data | instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/location_data/custom_field_id |
outlet | parent block's id | instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@block_id |
outlet | parent block's name | instance('locations')/locations/location[@id = instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@block_id]/name |
outlet | parent block's name | instance('locations')/locations/location[@id = instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@block_id]/site_code |
outlet | parent district's id | instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@district_id |
outlet | parent district's name | instance('locations')/locations/location[@id = instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@district_id]/name |
block | parent district's id | instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@district_id |
block | parent district's name | instance('locations')/locations/location[@id = instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@district_id]/name |
district | parent state's id | instance('locations')/locations/location[@id = instance('commcaresession')/session/user/data/commcare_location_id]/@state_id |
Accessing the location additional information (Location Fields)
Once you have the location's ID you can access it to get other information.
These examples assume your ID is stored in a hidden value called location_id
Referencing... | syntax in forms |
---|---|
The gps of the location | instance('locations')/locations/location[@id = /data/location_id]/latitude instance('locations')/locations/location[@id = /data/location_id]/longitude |
Any custom location fields you may have (ex. admin name) | instance('locations')/locations/location[@id = /data/location_id]/location_data/admin_name |
Making select questions with locations as choices
You can use the location hierarchy to make select questions that allow you to choose a location in a form. The process is similar to setting up multiple choice questions with cases as choices.
Go to Application Settings to turn on the Custom Single and Multiple Answer Add-On in the "Calculations" section.
Add a new "multiple choice lookup table" question
In the "lookup table data" choose the 3 dots next to the list of lookup tables
Set the query to: instance('locations')/locations/location[@type = 'TYPE OF LOCATION'] NOTE: "type of location" is given for each organization level by the "type code." You can see the type code when you click on "Advanced Mode" on the Organization Levels page.
Set the instance ID to locations
Set the instance URI to jr://fixture/locations
Hit save
Set the value to "@id" and the label to "name"
Tiered Location Selection
You can also add tiered selection (e.g. select state, then district, then block) by adding multiple select questions after each other as described above. Assuming the example of districts and block:
Setup the district list as described above (this example assumes the question_id is district)
Add a second multiple choice question, and configure it to display a list of blocks
In the filter section, add a filter with the following: @district_id = /data/district
Example location fixture structure
Example locations fixture
<fixture id="locations" indexed="true" user_id="b43e50ca1c3174fe0bbcf36cfd93a1eb">
<locations>
<location id="999dc78d9ca84ea8749dc75b44542332"
type="country"
country_id="999dc78d9ca84ea8749dc75b44542332"
state_id=""
county_id=""
city_id="">
<name>USA</name>
<site_code>usa</site_code>
<external_id/>
<latitude/>
<longitude/>
<location_type>country</location_type>
<supply_point_id/>
<location_data>
<name-en>USA</name-en>
<name-es>USA</name-es>
<is_test/>
</location_data>
</location>
<location id="999dc78d9ca84ea8749dc75b44541bdc"
type="state"
country_id="999dc78d9ca84ea8749dc75b44542332"
state_id="999dc78d9ca84ea8749dc75b44541bdc"
county_id=""
city_id="">
<name>Massachusetts</name>
<site_code>massachusetts</site_code>
<external_id/>
<latitude/>
<longitude/>
<location_type>state</location_type>
<supply_point_id/>
<location_data>
<is_test/>
</location_data>
</location>
<location id="999dc78d9ca84ea8749dc75b44540257"
type="county"
country_id="999dc78d9ca84ea8749dc75b44542332"
state_id="999dc78d9ca84ea8749dc75b44541bdc"
county_id="999dc78d9ca84ea8749dc75b44540257"
city_id="">
<name>Middlesex</name>
<site_code>middlesex</site_code>
<external_id/>
<latitude/>
<longitude/>
<location_type>county</location_type>
<supply_point_id/>
<location_data>
<name-en>Middlesex</name-en>
<name-es>Middlesex</name-es>
<is_test/>
</location_data>
</location>
<location id="999dc78d9ca84ea8749dc75b4453ff5b"
type="city"
country_id="999dc78d9ca84ea8749dc75b44542332"
state_id="999dc78d9ca84ea8749dc75b44541bdc"
county_id="999dc78d9ca84ea8749dc75b44540257"
city_id="999dc78d9ca84ea8749dc75b4453ff5b">
<name>Cambridge</name>
<site_code>cambridge</site_code>
<external_id/>
<latitude/>
<longitude/>
<location_type>city</location_type>
<supply_point_id/>
<location_data>
<is_test/>
</location_data>
</location>
</locations>
</fixture>
Syncing more of location hierarchy to users
By default, CommCare will only send each user the list of their assigned locations and those location's ancestors and descendants. For example, if I'm assigned to a block, I will get a list of my state, my district, my block and all that blocks outlets.
In some situations, you may want to get a list of locations outside of the ancestors and descendants. In the example above, if a user is assigned to a block, they may want to see all districts in that state anyway. This is controlled using the "Expand From" options outlined on https://dimagi.atlassian.net/wiki/x/GW-Kfw.