...
A form is a collection of fields classified through pages
, sections
and questions
. These fields are rendered differently based on their associated question type
and rendering
. For example, a text
field dropdown will behave differently than from a dropdown
.
Forms are described using JSON schemas that conform to the O3 standard JSON schema spec. This standard JSON schema ensures that schemas built using either the Angular or React form engines have parity. Below is an example of a form rendered using the Form Engine:
...
Element | Type | Description |
---|---|---|
| string | The name of the form. This is required and should be unique within the system. |
| string | The unique form identifier |
| string | The encounter type |
| single-line / multi-line / automatic | The inline rendering mode |
| Array<Section> | A collection of pages that make the form. Each page contains sections and questions. |
| Array<Intent> | A list of intents supported by this form. Intents define specific actions associated with the form. |
Pages
A page is a collection of related sections. A typical page definition consists of a label
, inlineRendering
(optional) and a list of section
s. The engine uses the page
’s label to identify it from other pages; that being said, it’s mandatory to keep the page’s label unique. Below is an example of a form with one page
and section
. The section
has 4 questions labelled:
...
Additional form properties
| array of objects | These are the conditions that validate the input data. |
| string/ number/boolean,/object | Default values for fields in the form. |
| boolean | Fields that must be filled out or selected. |
| string | Expression or data related to historical information. |
| object | The option to hide certain parts of the form or fields. |
| string | Expressions that calculate values based on inputs. |
| string | These are additional information or context about a question. |
| array of objects | Responses or answers provided in the form. |
| string | Type of order or sequence for form elements. |
| array of objects | Orders that can be selected or applied. |
| array of objects | This is the mapping of concepts to specific form elements. |
| string | Identifier for a specific concept within the form. |
Pages
A page is a collection of related sections. A typical page definition consists of a label
, inlineRendering
(optional) and a list of section
s. The engine uses the page
’s label to identify it from other pages; that being said, it’s mandatory to keep the page’s label unique. Below is an example of a form with one page
and section
. The section
has 4 questions labelled:
Code Block | ||
---|---|---|
| ||
{ "name": "HTS Retrospective Form", "pages": [ { "label": "Eligibility Screening", "sections": [ { "label": "Testing history", "isExpanded": "true", "questions": [ { "label": "What is the reason for conducting the HIV test?", "type": "obs", "questionOptions": { "rendering": "select", "concept": "ce3816e7-082d-496b-890b-a2b169922c22", "answers": [ { "concept": "7398c91a-8db8-480d-8130-1a92cc208ded", "label": "Inconclusive HIV Result", "conceptMappings": [] }, { "concept": "a6ad599d-2bc4-47b7-81fe-a38e88867c1d", "label": "Self Initiative", "conceptMappings": [] }, { "concept": "0e65e5fd-a1d8-4730-a991-75a1d703cba6", "label": "HIV Self Test Positive", "conceptMappings": [] }, { "concept": "6e768c50-a239-45ff-9920-2c6a9352320e", "label": "Index Client Testing", "conceptMappings": [] }, { "concept": "cb099534-b609-4561-9d4c-dd2fc74cedaf", "label": "Assisted Partner Notification (APN)", "conceptMappings": [] }, { "concept": "5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "label": "Other" } ] }, "id": "reasonForTesting" }, { "label": "Has the client ever been tested for HIV?", "type": "obs", "questionOptions": { "rendering": "radio", "concept": "1492AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "answers": [ { "label": "Yes", "concept": "cf82933b-3f3f-45e7-a5ab-5d31aaee3da3" }, { "label": "No", "concept": "488b58ff-64f5-4f8a-8979-fa79940b1594" }, { "concept": "1067AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "label": "Unknown" } ] }, "id": "everTestedForHIV" }, { "label": "How recently has the client been tested for HIV within any of the following periods?", "type": "obs", "questionOptions": { "rendering": "select", "concept": "e7947a45-acff-49e1-ba1c-33e43a710e0d", "answers": [ { "concept": "909edba5-c9b1-44e3-92ee-f95269964fe1", "label": "0-3 Months", "conceptMappings": [] }, { "concept": "8df190d5-7a65-4b53-9b4a-b35b9cf400b1", "label": "3-6 Months", "conceptMappings": [] }, { "concept": "c85e6df3-7184-400e-a686-f41aaae08113", "label": "6-12 Months", "conceptMappings": [] }, { "concept": "8de5bf3f-8058-4735-ae50-b5a986b2362b", "label": "More Than 12 Months", "conceptMappings": [] }, { "concept": "1067AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "label": "Unknown" } ] }, "id": "durationSinceLastHIVTest" }, { "label": "What was the result of the last HIV test?", "type": "obs", "questionOptions": { "rendering": "select", "concept": "159427AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "answers": [ { "concept": "6378487b-584d-4422-a6a6-56c8830873ff", "label": "Positive", "conceptMappings": [] }, { "concept": "664AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "label": "Negative" }, { "concept": "7398c91a-8db8-480d-8130-1a92cc208ded", "label": "Inconclusive", "conceptMappings": [] }, { "concept": "1067AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "label": "Unknown" } ] }, "id": "lastHIVTestResult" } ] } ] } ], "uuid": "xxxx", "encounterType": "79c1f50f-f77d-42e2-ad2a-d29304dde2fe" } |
...
label
: The actual content of the question. This label is what gets rendered as the question label. If no label is specified, the "display" value of the concept is used (which is generally the preferred name for the concept in the current locale)type
: Provides information of how the submission value will be processed. It helps the engine map the target submission handler to a field. Currently supported types include: obs | obsGroup | encounterLocationobs
: questions of thistype
will yield an observation as a submit-able.obsGroup
: questions of thistype
will yield an obs group as a submit-able.encounterLocation
: questions of thistype
will capture a location that will be associated to the current encounter.
questionOptions
: An object defining other properties of a question:rendering
: The field type of the question. Currently supported types include: select | text | date | number | checkbox | radio | repeating | group | content-switcher | encounter-location | textarea | toggle | fixed-value read more about supported types.concept
: The concept UUID or concept reference mapping in the format "source:term" (for example "CIEL:1234") of the backing concept for this field.defaultValue
: The default value to be associated to this question.answers
: An array of answers scoped to a question. An answer definition consists of a concept UUID or mapping and label pair. If no label is specified, the "display" value of the concept is used. Below is an example of answers to aCurrent HIV status
question:
questionInfo
: A property that recieves a string containing additional information regarding the field. When hovered over, it displays a tooltip containing the information passed.Code Block language json { "questionInfo": "sample tooltip info for text" }
isHidden
: A boolean value that determines field visibility. In most cases, this value is driven by hide expressions.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:Code Block language json { "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 }
required
: If settrue
, that form field is considered to be mandatory. Defaults to false.unspecified
: If settrue
, the form engine will render a widget(as part of this field) that can be used to mark this field as unspecified. By default, a mandatory field can't pass validation without a validvalue
. However, think of a scenario where it’s almost impossible to provide a value eg. when filling out a form in retrospective where a value wasn’t collected on the paper form. For such scenarios, arequired
field can be marked asunspecified
.
Note |
---|
What is the value of Unspecified? Unspecified does not create an observation in the database. It is the equivalent of a NULL value in database systems (but does not create a NULL value). Unspecified is not a concept. It is rendered by the form engine and not persisted in the database. |
validators
: Anarray
in which you provide validation logic for the specific question. Learn more about validators.behaviours
: Anarray
of supported behaviours. Learn more about form behaviours.locale)type
: Provides information of how the submission value will be processed. It helps the engine map the target submission handler to a field. Currently supported types include: obs | obsGroup | encounterLocationobs
: questions of thistype
will yield an observation as a submit-able.obsGroup
: questions of thistype
will yield an obs group as a submit-able.encounterLocation
: questions of thistype
will capture a location that will be associated to the current encounter.
questionOptions
: An object defining other properties of a question:rendering
: The field type of the question. Currently supported types include: select | text | date | number | checkbox | radio | repeating | group | content-switcher | encounter-location | textarea | toggle | fixed-value read more about supported types.concept
: The concept UUID or concept reference mapping in the format "source:term" (for example "CIEL:1234") of the backing concept for this field.defaultValue
: The default value to be associated to this question.answers
: An array of answers scoped to a question. An answer definition consists of a concept UUID or mapping and label pair. If no label is specified, the "display" value of the concept is used. Below is an example of answers to aCurrent HIV status
question:
questionInfo
: A property that recieves a string containing additional information regarding the field. When hovered over, it displays a tooltip containing the information passed.Code Block language json { "questionInfo": "sample tooltip info for text" }
isHidden
: A boolean value that determines field visibility. In most cases, this value is driven by hide expressions.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:Code Block language json { "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 }
required
: If settrue
, that form field is considered to be mandatory. Defaults to false.unspecified
: If settrue
, the form engine will render a widget(as part of this field) that can be used to mark this field as unspecified. By default, a mandatory field can't pass validation without a validvalue
. However, think of a scenario where it’s almost impossible to provide a value eg. when filling out a form in retrospective where a value wasn’t collected on the paper form. For such scenarios, arequired
field can be marked asunspecified
.
Note |
---|
What is the value of Unspecified? Unspecified does not create an observation in the database. It is the equivalent of a NULL value in database systems (but does not create a NULL value). Unspecified is not a concept. It is rendered by the form engine and not persisted in the database. |
validators
: Anarray
in which you provide validation logic for the specific question. Learn more about validators.behaviours
: Anarray
of supported behaviours. Learn more about form behaviours.isTransient
The RFE supports the ability to make a form field transient. Making a field transient means that the data entered into the form is not saved permanently. This functionality can be easily integrated into the JSON format, as demonstrated below.
Code Block |
---|
"questionOptions": {
"isTransient": "true",
"rendering": "date",
"concept": "160555AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
}, |
Components
...
There may be situations where you might want to separate commonly-used form logic into separate reusable bits. In such cases, you can structure that logic as a component form. Components can therefore be thought of as reusable forms that carry domain-specific information. Imagine a situation where you're creating many forms for use in a Point of Care setting. You might find that multiple forms might need to have sections for collecting pre-clinic Review information. This pre-clinic Review information could include details such as:
...