Skip to content

Skip Logic Relevance View visibility toggle

Benjamin Mwalimu edited this page Jun 9, 2020 · 1 revision

Skip Logic/Relevance - View visibility toggle

Skip Logic is defined using the "relevance" value. This enables a field to be shown only if the condition set in 'ex' is True

Legacy skip logic

"relevance": {
          "step1:Place_Birth": {
            "type": "string",
            "ex": "equalTo(., \"Health facility\")"
          }
        }

The field above will only be shown if the value for field whose key is Place_Birth, which is the Patient's Place of Birth (Location), is equals to "Health Facility"

      {
        "key": "isDateOfBirthUnknown",
        "openmrs_entity_parent": "",
        "openmrs_entity": "",
        "openmrs_entity_id": "",
        "type": "check_box",
        "label": "",
        "options": [
          {
            "key": "isDateOfBirthUnknown",
            "text": "DOB unknown?",
            "value": "false"
          }
        ]
      }
        "relevance": {
          "step1:isDateOfBirthUnknown": {
            "type": "string",
            "ex": "equalTo(., \"true\")"
          }
        }

The above is an example showing an example with a checkbox field

The following are the available comparators:

  • Equal To - equalTo
  • Greater Than - greaterThan
  • Greater Than or Equal To - greaterThanEqualTo
  • Less Than - lessThan
  • Less Than or Equal To - lessThanEqualTo
  • Not Equal To - notEqualTo
  • Regex Comparison - regex

The comparators work on the following variable types:

  • String - string
  • Numeric numeric - Integer, double, float ...
  • Date date - In the format dd-MM-yyyy
  • Array array - Arrays are said to be similar if:
    • Have the same number of items
    • Have same items in equal number, irrespective of index

The syntax for the comparison expression ex:

equalTo(., "Health facility")

is as follows:

comparator($value1, $value2)

$value1 is supposed to be a dot . so that the value $value1 is that of the referenced field --> Place_Birth in step1.

The field reference/identifier uses the field's key attribute

Skip logic for Checkbox group widget

Check boxes can also be selected multiple times . The corresponding skip logic can also thus become complex. In the example below, (present in the sample app), the CHW Phone Number Widget will only show based on these various conditions:

  1. Severe Bleeding is checked
  2. Both Perineal Tear and Placenta Previa are checked
  3. Both Cord Prolapse and Abnormal Presentation checked or just Prolonged Obstructed Labour is checked

The implementation introduces a new field ex-checkbox which contains the complex checkbox expression, the example for the above 3 conditions is as below. The relevant keys of the multi-select checkbox are specified as arrays wrapped with an object key of either and or or or both to be used for simple boolean logic processing.

,
        "relevance": {
          "step1:delivery_complications": {
            "ex-checkbox": [
              {
                "or": ["severe_bleeding"]
              },
              {
                "and": ["perineal_tear","placenta_previa"]
              },
              {
                "and": [
                  "cord_prolapse",
                  "abnormal_presentation"
                ],
                "or": [
                  "prolonged_obstructed_labour"
                ]
              }
            ]
          }

   {
        "key": "delivery_complications",
        "openmrs_entity_parent": "",
        "openmrs_entity": "concept",
        "openmrs_entity_id": "161641AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
        "openmrs_data_type": "select one",
        "type": "check_box",
        "label": "Any delivery complications?",
        "label_text_size": "18sp",
        "label_text_color": "#FF9800",
        "hint": "Any delivery complications?",
        "exclusive": ["none"],
        "options": [
          {
            "key": "none",
            "text": "None",
            "value": false,
            "openmrs_choice_id": "160034AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
          },
          {
            "key": "severe_bleeding",
            "text": "Severe bleeding/Hemorrhage",
            "value": false,
            "openmrs_choice_id": "160034AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
            "text_color": "#000000"
          },
          {
            "key": "placenta_previa",
            "text": "Placenta previa",
            "value": false,
            "openmrs_choice_id": "160034AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
            "text_size": "30sp"
          },
          {
            "key": "cord_prolapse",
            "text": "Cord prolapse",
            "value": false,
            "openmrs_choice_id": "160034AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
            "text_size": "10sp"
          },
          {
            "key": "prolonged_obstructed_labour",
            "text": "Prolonged/obstructed labour",
            "value": false,
            "openmrs_choice_id": "160034AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
          },
          {
            "key": "abnormal_presentation",
            "text": "Abnormal presentation",
            "value": false,
            "openmrs_choice_id": "160034AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
            "text_color": "#FF9800"
          },
          {
            "key": "perineal_tear",
            "text": "Perineal tear (2, 3 or 4th degree)",
            "value": false,
            "openmrs_choice_id": "160034AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
          },
          {
            "key": "other",
            "text": "Other",
            "value": false,
            "openmrs_choice_id": "160034AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
          }
        ],
        "v_required": {
          "value": "false"
        }
      }

The above relevance example shows a multiple select checkbox example and its used in the sample demo app for the CHW_Phone_Number widget.

If you want to specify relevance on the basis of whether a particular value HAS NOT been checked/selected use the not key field as shown below. Here, the widget will not show if the severe bleeding option has been selected

  "relevance": {
          "step1:delivery_complications": {
            "ex-checkbox": [
              {
                "not": ["severe_bleeding"]
              }]
           }

Skip logic using the rules engine

OpenSRP Client Native Forms is now integrated with a rules engine for skip logic. We use the J-Easy Library which can be found Here. Rules are defined in yaml configuration files that are stored in the assets/rule folder. You can define multiple rules in multiple configs to be used by one json form

When defining the skip logic for your forms keep relevance in separate files. e.g if i am doing a form called physical_exam , under assets/rules i should have two files namely physical-exam-relevance-rules.yml

You can name the files any thing you want so long as you don't mix calculations and relevance definitions.

Separating and naming the files this way per form is however the recommended approach

The j-easy library uses MVEL expression language which is java like to define its rules. There are a few subtle differences but those can be found in the MVEL Documentation Here

Once you have the rules defined, you need to reference them like this in the form's json

{
        "key": "happiness_level",
        "openmrs_entity_parent": "",
        "openmrs_entity": "person_attribute",
        "openmrs_entity_id": "relevance_happiness_level",
        "type": "edit_text",
         "relevance": {
           "rules-engine": {
             "ex-rules": {
               "rules-file": "sample-relevance-rules.yml"
             }
           }
         }
      }

In the example above, the relevance for the edit text with key happiness_level are defined in the assets/rule/sample-relevance-rules.yml.

The Sample App now has the various sections separated for easier reference. Once you run the app , clicking on the RULES ENGINE LOGIC button guides you through various configurations for relevance and calculations. You can check out the corresponding rules files under assets/rule to see how they are configured.

NB:

  • When defining rules, always prefix with the step name they reference e.g. if its a key age in step 1 then the field reference in the condition should be as step1_age e.g. condition: "step1_hepb_immun_status < 60 || step1_hepb_immun_status > 100" or if field contains a value which is a list like the checkbox widget step2_super_heroes.contains('batman')
  • The name of the rule should be the key of the field it configures also be prefixed with its step e.g. name: step1_happiness_level
  • The action of a relevance should always be an assignment to the key is relevant e.g.
    actions:
     - "isRelevant = true"
    

You can also inject global values in the root of the json form and they can be used during the relevance evaluations. useful e.g. if you want to inject external settings that are part of the logic

,
 "global": {
   "has_cat_scan": true,
   "stock_count": 100
 },

Here is complete example definition of the relevance for happiness_level. Its value depends on the first name from step 1 being set to Martin (case sensitive) and a global value for has_cat_scan being set to true.

name: step1_happiness_level
description: Happiness level relevance
priority: 1
condition: "step1_First_Name == 'Martin' && global_has_cat_scan == 'true' "
actions:
  - "isRelevant = true"