All the details of capturing observation using the techniques mentioned below are relevant to Forms 1.0 technology, based on "ConceptSet UI". For Forms 2.0 based techniques of defining a form please refer here. |
Observation forms (also referred to as templates) are used to capture observations during an encounter in a pre-defined format. One can define observation forms to capture both general/non-disease-specific (e.g. Operation notes) information and condition/disease specific (e.g. Anaemia) information.
To the user, an observation form shows up as an input form in the "Consultation" user interface, while in the back end, the observation form is modeled as a concept set. The form elements can be customized by defining/modifying concepts within the concept set. They can also be customized by adding configuration in implementation-config such as Multiselect, Add more, etc.
Sample Screenshot of Observation Form
Follow these recommended guidelines to define observation forms:
|
You can watch this video on how to create a simple Observation / Clinical Form in Bahmni using the OpenMRS UI: Youtube Video (Creating Observation / Clinical Forms in Bahmni) |
There are two ways to add Observation Forms to Bahmni:
Bahmni supports the ability to import Observation Forms via CSV Upload function in Admin Module. Please refer to the screenshot below:
Sample CSVs:
Few CSV examples for Observation Templates and generic concepts can be found at:
https://github.com/Bhamni/default-config/tree/master/openmrs/templates
https://github.com/anantraut/possible-config/tree/master/openmrs/templates
To configure Disease Template Concept Sets, perform the following step in OpenMRS:
"visitTypeForRetrospectiveEntries": "GENERAL", "conceptSetUI": { "Consent scan copy" : { "allowAddMore" : true }, "Baseline, List of drugs taken for more than a month": { "multiSelect": true }, "Baseline, Disease site": { "multiSelect": true }, "Baseline, Patients for whom the construction of a regimen with four likely effective second-line drugs is not possible": { "multiSelect": true }, "Baseline, Other patients who have high risk of unfavorable outcome but who do not fit the above categories": { "multiSelect": true }, "Baseline, Method of MDR-TB confirmation" : { "multiSelect" : true } } |
Please refer to https://github.com/Bhamni/endtb-config/blob/master/openmrs/apps/clinical/app.json in case of requirement of additional information.
The table below explains how various Concept Data types work with examples
Type | Example | |
---|---|---|
1 | Coded - Autocomplete with only coded values Usage: Use it when you have fixed set of answers for a concept | "Death Note, Primary Cause of Death": { Where, "Death Note, Cause, Answers" = Concept which has answers** |
2 | Coded - Autocomplete with multi select. This feature is configurable only for the coded concepts and parent of the concept shouldn't be of class "ConceptDetails" type. Default behavior will be button select. | "Fully specified name of the concept": { Example : "New Born status": { |
3 | Coded - Autocomplete with coded values and non-coded values | Using the example of Chief Complaints, here is the OpenMRS concept hierarchy:
All the coded answers should be added to Chief Complaint Answers and not Chief Complaint. This is a hack as loading children when loading a concept, slows down the loading of the form. "Chief Complaint Data": { If either of codedConceptName or nonCodedConceptName is not given, It will be treated as autocomplete with only coded values. The name of this configuration can be either "multiSelect": true instead of "autocomplete": true |
4 | Coded - Dropdown with only coded values Usage: Use it when you have a smaller set of answers for a concept | "Death Note, Primary Cause of Death": { |
5 | Coded - Button Select with only coded values Usage: Use it when you have a small set of answers for a concept | "Death Note, Primary Cause of Death": { |
6 | Text - Free text type | "Chief Complaint Notes": { |
7 | Boolean - For Yes/No type | "Posture" : { |
8 | Numeric - For numerical values Usage: Recommended to be configured only when the numbers would be small like number of children, pregnancies etc | "No of children" : { |
9 | Date - For dates (without time) | |
10 | Datetime - For dates with time | |
11 | N/A - No data type Usage: This is used for concepts which are used as answer to some other concept | |
12 | answersConceptName | It is an optional field. If it is not configured, then the same concept's answers will be picked. Example: "Death Note, Primary Cause of Death": { Where, "Death Note, Primary Cause of Death" = Concept which has answers |
Steps:
Notes:
Any concept in the parent concept set can be enabled / disabled conditionally based on the other concepts value. This makes the long forms usable and intuitive to use.
In the example below, "Chief Complaint Notes" is editable only if "Chief Complaint" concept is filled:
The configuration to conditionally enabling/ disabling concepts based on value of other concepts (as shown in the image) is shown below (formConditions.js):
// Bahmni.ConceptSet.FormConditions.rules is a map with key as the <concept name> that matches with the currently changed element in the observation form Bahmni.ConceptSet.FormConditions.rules = { '<concept name>': function(formName, formFieldValues) { // This function gets 2 parameters // 'formName' will be the concept name of the form in which a value has been changed. ("History and Examination" in the above gif) // 'formFieldValues' is a map with key as concept name and value as its current value // All the editable fields like 'Chief Complaint', 'Chief Complaint Notes', 'History Notes' will be present with their values as seen on the screen return {enable: [], disable: []}; // This method SHOULD return a map with two keys 'enable' and 'disable' with string array containing the concept names that needs to be enabled or disabled } |
Example:
Bahmni.ConceptSet.FormConditions.rules = { //This is a constant that Bahmni expects 'Chief Complaint Data': function(formName, formFieldValues) {//'Chief Complaint Data' concept when edited, triggers this function var conditions = {enable: [], disable: []}; var chiefComplaint = formFieldValues['Chief Complaint']; var nonCodedChiefComplaint = formFieldValues['Non-Coded Chief Complaint']; if(chiefComplaint || nonCodedChiefComplaint) { conditions.enable.push("Chief Complaint Notes") } else { conditions.disable.push("Chief Complaint Notes") } return conditions; //Return object SHOULD be a map with 'enable' and 'disable' arrays having the concept names } }; |
Enable or disable form elements based on multi-select
Bahmni.ConceptSet.FormConditions.rules = { 'Tuberculosis, Type': function(formName, formFieldValues) { var conditions = {enable: [], disable: []}; var selectedValues = formFieldValues['Tuberculosis, Type']; var found = _.contains(selectedValues, "Pulmonary") && _.contains(selectedValues, "Extrapulmonary") if(found) { //conditions } else { //conditions } } }; |
When large amount of information is captured, the forms grow in size, the user would need to do significant amount of scrolling to get to relevant fields where data is to be entered. By using the config as below it is possible to show/hide fields in the form based on form conditions.
One can configure show/hide and enable/disable conditional observation forms at the same time for different concepts.
You may have a look at this file here for reference: https://github.com/Bhamni/default-config/blob/master/openmrs/apps/clinical/formConditions.js
The configuration to conditionally show/ hide concepts based on value of other concepts is shown below (formConditions.js):
'<Concept Name>': function (formName, formFieldValues) { // This function gets 2 parameters // 'formName' will be the concept name of the form in which a value has been changed. ("History and Examination" in the above gif) // 'formFieldValues' is a map with key as concept name and value as its current value // All the editable fields like 'Chief Complaint', 'Chief Complaint Notes', 'History Notes' will be present with their values as seen on the screen return {show: [], hide: []}; // This method SHOULD return a map with two keys 'show' and 'hide' with string array containing the concept names that needs to be enabled or disabled } |
Bahmni.ConceptSet.FormConditions.rules = { //This is a constant that Bahmni expects 'Chief Complaint Data': function(formName, formFieldValues) {//'Chief Complaint Data' concept when edited, triggers this function var conditions = {show: [], hide: []}; var chiefComplaint = formFieldValues['Chief Complaint Data']; var nonCodedChiefComplaint = formFieldValues['Non-Coded Chief Complaint']; if(chiefComplaint || nonCodedChiefComplaint) { conditions.show.push("Chief Complaint Notes") } else { conditions.hide.push("Chief Complaint Notes") } return conditions; //Return object SHOULD be a map with 'show' and 'hide' arrays having the concept names } }; |
When “displayMonthAndYear” is set to true for a concept of type ‘date', the concept allows user to select month and year in dropdown. The years between minYear and and maxYear are shown in the dropdown. By default, the date will be set to first of the month. When minYear is not configured, default minYear is 15 years from current year. When maxYear is not configured, default maxYear is 5 years from current year by default. When “displayMonthAndYear” is set to false or not configured, date will be the default date picker.
"config" : { "conceptSetUI": { "Malaria, Treatment Start Date" : { "minYear": 1999, "maxYear": 2019, "allowFutureDates": true, "displayMonthAndYear": true } } } |
Configure "Add more" button
"Add more" button allows the user to fill multiple instances of the same form in one go. This is achieved by clicking on the "Add more" button at the top right corner of the form.
"config" : { "conceptSetUI": { "Adverse Events Template": { "allowAddMore": true } } } |
It is used to view the observation page in tabular view
"config" : { "conceptSetUI": { "Adverse Events": { "isTabular": true } } } |