Questions
A question is a field in a Form. It consists of a label, an associated input, and a set of answers.
Below is an example of a question that seeks to establish the patient's Current HIV status
:
{
"questions": [
{
"label": "Current HIV status",
"type": "obs",
"id": "hivStatus",
"questionOptions": {
"rendering": "select",
"concept": "9e4d6436-4040-46a3-a0ae-6dbc0acfe593",
"answers": [
{
"concept": "a896f3a6-1350-11df-a1f1-0026b9348838",
"label": "HIV positive"
},
{
"concept": "a896d2cc-1350-11df-a1f1-0026b9348838",
"label": "HIV negative"
},
{
"concept": "a899b50a-1350-11df-a1f1-0026b9348838",
"label": "Unknown"
}
]
},
"validators": []
}
]
}
Defining a question
Here's a reference of the various properties you can specify in a question definition:
-
label
: The actual content of the question. This label is what gets rendered as the question label. -
id
: An ID unique to that question. Used when validating the field input. It's recommended to use camel-case for your ID names. -
type
: Provides information that the processor uses to render a field. Anobs
field, for example, will be rendered differently than anencounterLocation
field. Learn more about the supported types in the question types reference below. -
questionOptions
: An object containing the following properties:-
rendering
: The field type of the question. The most commonly used field types are text (for text inputs), select (for select fields) and date (for date fields). See the Field types reference for a full list of rendering types. -
concept
: The concept UUID of the backing concept for this field. You can get this concept UUID from searching in the Concept Dictionary. -
answers
: An array of answers scoped to a question. An answer definition consists of a concept UUID and label pair. Below is an example of answers to aCurrent HIV status
question:{ "answers": [ { "concept": "a896f3a6-1350-11df-a1f1-0026b9348838", "label": "HIV positive" }, { "concept": "a896d2cc-1350-11df-a1f1-0026b9348838", "label": "HIV negative" }, { "concept": "a899b50a-1350-11df-a1f1-0026b9348838", "label": "Unknown" } ] }
-
calculate
: An object where you can specifycalculateExpressions
. These are predefined expression helpers that take inputs and return numeric values. Read more aboutcalculateExpressions
in the Performing Calculations guide.{ "label": "BMI (Kg/M2):", "id": "bmi", "questionOptions": { "rendering": "number", "concept": "a89c60c0-1350-11df-a1f1-0026b9348838", "max": "100", "min": "0", "calculate": { "calculateExpression": "calcBMI(height,weight)" } }, "type": "obs", "validators": [] }
-
-
shownDateOptions
- A property that determines whether a date field should be shown or hidden based on the value of another date field. This property receives an object with the following properties:{ "questionOptions": { // ... rest omitted for brevity "shownDateOptions": { "validators": [ { "type": "date" }, { "type": "js_expression", "failsWhenExpression": "!isEmpty(ast_test) && isEmpty(myValue)", "message": "Date of result is required" } ], "hide": { "hideWhenExpression": "isEmpty(ast_test)" } } } }
-
required
- A property that determines whether a field is required or optional. Required fields must be filled before the form can be submitted. This property receives either a boolean value or an object. If a boolean value is provided,true
marks the question as required whereasfalse
marks the question as optional. In this case, the required property defaults to false, meaning all fields start out as optional by default. If set to true, that form field is considered a required field. Defaults tofalse
. If the value provided is an object, it will have the following properties:type
- defaults toconditionalRequired
.message
- a string that gets displayed when as an error message below the field if a condition is not met.referenceQuestionId
- The ID of a question in the schema that relates to this particular question. When type is set toconditionalRequired
, the question referenced by this ID is used to evaluate a condition that involves the answers set in thereferenceQuestionAnswers
array below.referenceQuestionAnswers
- an array of concept UUIDs that reference answers linked to the question referenced byreferenceQuestionId
. If the linked question gets answered with any of the answers in the array and the question with theconditionalRequired
validation does not get answered, validation fails and the error message inmessage
above gets displayed below the field.
{ "required": { "errorMessage": "Please enter a value for this field", "conditionalRequired": [ { "questionId": "onArt", "response": "a899b35c-1350-11df-a1f1-0026b9348838", "errorMessage": "Please enter a value for this field" } ] } }
-
validators
: An array in which you provide validation logic for the specific question. Read more about validation in the Validation guide. -
historicalExpression
: This allows you to hook your input up to theHistoricalEncounterDataService
. This service 'remembers' the last value entered in the input from the last encounter and offers the user the option to reuse that value. Read more abouthistoricalExpressions
in the Historical expressions guide. -
hide
: You can use this to define logic for hiding a question based on certain conditions. To do so, you provide a JavaScript expression that evaluates to a boolean value. Read more about hiding fields in the Hiding fields guide.{ "hide": { "hideWhenExpression": "onArt!== 'a899b35c-1350-11df-a1f1-0026b9348838'" } // This logic hides the question with the `onArt` id if the value of its // concept does not match the supplied value }
-
questionInfo
: You can specify helper text for the question here. When specified, a question mark icon gets displayed to the right of the question label. When you hover over it, the information you entered gets displayed as a tooltip. This is useful for providing additional context to the user about a question.The code for this is as follows:
{ "label": "Person Collecting Medication", "questions": [ { "label": "Visited by:", "id": "visitBy", "questionInfo": "Record the person that came for the clinic today, whether it is the patient or the treatment supporter.", "questionOptions": { "rendering": "select", "concept": "a89cd410-1350-11df-a1f1-0026b9348838", "answers": [ { "concept": "a898c6f4-1350-11df-a1f1-0026b9348838", "label": "Self" }, { "concept": "01b957da-23bb-4862-819d-036364fe3faf", "label": "Treatment supporter" } ] }, "type": "obs", "validators": [] } ] }
Question types
The following are the question types supported by the form engine:
control
control
questions typically use the text rendering type.
Here's an example of a control
field:
{
"label": "Morisky score rating:",
"id": "scoreMo",
"questionOptions": {
"concept": "",
"rendering": "text",
"calculate": {
"calculateExpression": "parseInt(moriskyScore) === 0 && parseFloat(moriskyScore) <= 0.25 ? 'Good' : parseFloat(moriskyScore) >=0.5 && parseInt(moriskyScore) <= 2 ? 'Inadequate' : parseInt(moriskyScore) >= 3 && parseInt(moriskyScore) <= 8 ? 'Poor' : 'Unknown'"
}
},
"type": "control",
"validators": [],
"hide": {
"hideWhenExpression": "isEmpty(moriskyScore4) || moriskyScore4 <3"
}
}
encounterDatetime
The encounterDatetime
question type is used to capture the date and time of an encounter. The corresponding rendering type for encounterDatetime
is date.
Here's an example of an encounterDatetime
field:
{
"label": "Visit date",
"type": "encounterDatetime",
"required": "true",
"default": "",
"id": "encDate",
"questionOptions": {
"rendering": "date"
},
"validators": [
{
"type": "date"
}
]
}
encounterLocation
The encounterLocation
question type is used to record the location of an encounter. encounterLocation
questions typically use the ui-select-extended rendering type. to render a dropdown list of locations.
Here's an example of an encounterLocation
field:
{
"type": "encounterLocation",
"label": "Facility name (site/satellite clinic required):",
"id": "location",
"required": "true",
"questionOptions": {
"rendering": "ui-select-extended"
}
}
encounterProvider
The encounterProvider
question type is used to record the provider of an encounter. encounterProvider
questions typically use the ui-select-extended rendering type to render a dropdown list of providers.
Here's an example of an encounterProvider
question:
{
"type": "encounterProvider",
"label": "Provider",
"id": "provider",
"required": "true",
"questionOptions": {
"rendering": "ui-select-extended"
}
}
obs
The obs
question type is used for capturing observations. obs
questions are linked to a concept and can have multiple answers. obs
fields are compatible with all rendering types.
Here's an example of an obs
question:
{
"label": "Current HIV status",
"type": "obs",
"id": "hivStatus",
"questionOptions": {
"rendering": "select",
"concept": "9e4d6436-4040-46a3-a0ae-6dbc0acfe593",
"answers": [
{
"concept": "a896f3a6-1350-11df-a1f1-0026b9348838",
"label": "HIV positive"
},
{
"concept": "a896d2cc-1350-11df-a1f1-0026b9348838",
"label": "HIV negative"
},
{
"concept": "a899b50a-1350-11df-a1f1-0026b9348838",
"label": "Unknown"
}
]
},
"validators": []
}
obsGroup
The obsGroup
question type is used to create an obs group. An obs group is used to link multiple obs
concpets together. obsGroup
questions require a grouping concept
, which must be of type ConvSet
. They may also be nested. obsGroup
fields typically use the group and repeating
rendering types.
Here's an example of an obsGroup
question:
{
"label": "TB Treatment Started, detailed",
"type": "obsGroup",
"questionOptions": {
"concept": "a89fe6f0-1350-11df-a1f1-0026b9348838",
"rendering": "group"
},
"questions": [
{
"label": "TB Treatment plan:",
"id": "tbTreatmentPlan",
"required": "true",
"questionOptions": {
"concept": "a89c1fd4-1350-11df-a1f1-0026b9348838",
"answers": [
{
"concept": "a899e0ac-1350-11df-a1f1-0026b9348838",
"label": "Not on TB treatment"
},
{
"concept": "a89b7908-1350-11df-a1f1-0026b9348838",
"label": "Continue regimen"
},
{
"concept": "a89b77aa-1350-11df-a1f1-0026b9348838",
"label": "Start induction"
},
{
"concept": "a89b7c50-1350-11df-a1f1-0026b9348838",
"label": "Change to continuation"
},
{
"concept": "a898c938-1350-11df-a1f1-0026b9348838",
"label": "Re-dose"
},
{
"concept": "a8a00158-1350-11df-a1f1-0026b9348838",
"label": "Substitution"
},
{
"concept": "a8a00220-1350-11df-a1f1-0026b9348838",
"label": "Restart"
},
{
"concept": "a89b7d36-1350-11df-a1f1-0026b9348838",
"label": "Stop"
}
],
"rendering": "select"
},
"type": "obs",
"validators": []
}
],
"id": "__vo5wMCKuD"
}
personAttribute
The personAttribute
question type is used to capture person attributes. personAttribute
fields require a backing person attribute type that's provided via the attributeType
field in the questionOptions
object. personAttribute
fields typically use the ui-select-extended rendering type to render a dropdown list of person attribute types.
Here's an example of a personAttribute
field:
{
"type": "personAttribute",
"label": "Specify which clinic the patient is being referred:",
"id": "clinicTransferredOutTo",
"required": "false",
"questionOptions": {
"rendering": "ui-select-extended",
"attributeType": "8d87236c-c2cc-11de-8d13-0010c6dffd0f"
},
"hide": {
"hideWhenExpression": "transferOut !== 'a89c2f42-1350-11df-a1f1-0026b9348838'"
}
}
testOrder
The testOrder
question type is used to capture test orders. testOrder
fields require an orderSettingUuid
and an orderType
in the questionOptions
object. The orderSettingUuid
is the UUID of the order setting to use when creating the order. The orderType
is the type of order to create. testOrder
fields typically use the repeating rendering type.
Here's an example of a testOrder
field:
{
"label": "Tests Ordered",
"id": "testsOrdered",
"type": "testOrder",
"questionOptions": {
"rendering": "repeating",
"orderSettingUuid": "6f0c9a92-6f24-11e3-af88-005056821db0",
"orderType": "testorder",
"selectableOrders": [
{
"concept": "a8982474-1350-11df-a1f1-0026b9348838",
"label": "Viral load"
},
{
"concept": "a896cce6-1350-11df-a1f1-0026b9348838",
"label": "CD4"
},
{
"concept": "7243bed9-0bc7-4702-af28-a06ab1981e19",
"label": "Crag test"
},
{
"concept": "57677735-4310-4841-8902-dae4bac24d20",
"label": "DST"
},
{
"concept": "a898fe80-1350-11df-a1f1-0026b9348838",
"label": "HIV DNA PCR "
},
{
"concept": "a8908192-1350-11df-a1f1-0026b9348838",
"label": "CXR"
},
{
"concept": "a8945d4e-1350-11df-a1f1-0026b9348838",
"label": "Sputum AFB"
},
{
"concept": "a897e450-1350-11df-a1f1-0026b9348838",
"label": "Creatinine"
},
{
"concept": "a898f50c-1350-11df-a1f1-0026b9348838",
"label": "CBC"
},
{
"concept": "a896ca48-1350-11df-a1f1-0026b9348838",
"label": "SGPT(ALT)"
},
{
"concept": "a896c8ae-1350-11df-a1f1-0026b9348838",
"label": "AST"
},
{
"concept": "a8970a26-1350-11df-a1f1-0026b9348838",
"label": " CD4 %"
},
{
"concept": "a8999fb6-1350-11df-a1f1-0026b9348838",
"label": "Elisa"
},
{
"concept": "a8999dfe-1350-11df-a1f1-0026b9348838",
"label": "Rapid HIV "
},
{
"concept": "a8a47094-1350-11df-a1f1-0026b9348838",
"label": "TB PCR "
},
{
"concept": "741517cf-8bac-4755-b289-8dd2a2df7962",
"label": "Gene Xpert"
}
]
}
}
patientIdentifier
The patientIdentifier
question type is used to capture patient identifiers. patientIdentifier
fields have a backing identifier type that's specified using the identifierType
property. patientIdentifier
fields typically use the text rendering type and typically validate the input against the specified identifier type.
Here's an example of a patientIdentifier
field:
{
"type": "patientIdentifier",
"label": "Recency ID",
"id": "recencyId",
"required": "false",
"questionOptions": {
"rendering": "text",
"identifierType": "fd52829a-75d2-4732-8e43-4bff8e5b4f1a"
},
"validators": [
{
"type": "js_expression",
"failsWhenExpression": "myValue && doesNotMatchExpression('^REC\\\\d{5}-\\\\d{5,6}$', recencyId)",
"message": "Please provide the correct format for the recency id ie. REC+mflCode+number eg.REC11902-00062"
}
],
"hide": {
"hideWhenExpression": "isEmpty(finalResult) || finalResult === '664AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' || isEmpty(recencyScreening) || recencyScreening === '1066AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' "
}
}