## Scripting & More Tab - Formula

### Generating a total score:

For example, if you were using the PHQ-9 questionnaire, you could put all of your questions into a section called "phq9q" and then use the following formula to calculate the sum of all of the scores in that section:

``ScriptUtil.sum(phq9Q)``

### Display a formula result:

If you would like to display the value calculated by your formula you can do so by adding "\$\$" to the "Caption" field (in the General tab). You can also use the "\$\$" in the "Custom Note" field (in the Note Formatting tab) if you don't want to display the value to the  patient but would like to capture it in the patient chart.

### More resources:

To learn how to round your formula answers to the nearest digit, please refer to: "Limiting the Number of Decimal Places in Formula Calculations".

For more examples of possible score calculations and more advanced scripting articles, please refer to:

## Scripting & More Tab - Show this field if

### Display a question, based on demographics:

If you are creating a general health assessment form and you want to ask about the possibility of pregnancy, you can choose to only show this field if the patient is female by entering the following into the "Show this field if" field:

``pt.isFemale()``

For a full list of available patient-related functions, please refer to: "ScriptPatient ("Pt") Functions".

### Display a question, based on how the patient responds to another question:

To determine if a smoking cessation counseling, you can first create an item that asks the patient whether or not they smoke and has item reference: "smoking".

If the answer is yes, you can show the next question, asking about whether or not they are interested in quitting, with the following in the "Show this field if" field:

``smoking.r == 'Y'``

Note: .r refers to that item’s response choice (e.g. “N” for no, “Y” for yes).

If you only want to show a follow-up question if a patient picks a menu choice, use the following ".r" value in combination with Javascript's String.indexOf() function in the "Show this field if" field:

``myMenuItem.r.indexOf("myAnswer") >= 0``

Note: In the above string, "myAnswer" is the specific menu choice that you wish to flag.

## Basics of JavaScript

### Basic Code

Symbol Meaning
== equals
!= not equals
|| or
&& and
> greater than
>= greater than or equal to
< less than
<= less than or equal to
() brackets control order of execution
. a period indicates a property of something
Case JavaScript is case-sensitive (i.e. capitalization matters!)

Any item that's been completed by a patient has 2 useful properties:

1. Response value ("r")
2. Point value ("p")

#### Accessing an Item's own Response Value

An item's own response value can be inserted into the caption or custom note of an item by using the string "\$\$". This is particularly useful when working with formula fields.

#### Examples:

myPainScale, a numeric scale with point values from 0-5.

myPainScale.r
Returns the value associated with the patient's choice (always in standard language, i.e. English)
myPainScale.p
Returns the point value as a number
\$\$
Returns the response value of that item when used in its own "Caption" or "Custom Note" fields (example caption field: "My Pain Scale Score: \$\$")

### Script Variables

Variable Description Example Expressions
pt The ScriptPatient object with age, sex, etc.
``pt.isMale() && pt.getAge() >= 55``

Refer to "ScriptPatient Functions" for more details about more "pt." expressions.

daysSinceLastCompleted The number of day since the patient last complete this form
``daysSinceLastCompleted > 365``
firstTime Whether or not the patient has ever completed this form
``firstTime``
lastCompletedTag A string “remembered” by the form last time it was completed
``lastCompletedTag.indexOf('myString') != -1``

### ScriptUtil Functions

ScriptUtil provides miscellaneous functions that allow you to simplify your scripts and support special use-cases. ScriptUtil is bound to all script session contexts, so you can use these functions in tablet rules or within eForms (show if, make note if, etc.)

Please refer to "ScriptUtil Functions" for examples of common ScriptUtil functions.

## ScriptPatient ("pt") Functions

The ScriptPatient functions are available on the "pt" object in any script context, such as a tablet rule or within an eForm Action script.

Function Description Example Expression (Boolean)
getAge() Returns age in years
``pt.getAge() > 40``
getAgeInMonths() Returns age in months
``pt.getAgeInMonths() > 18``
getAgeInWeeks() Returns age in weeks
``pt.getAgeInWeeks() > 6``
isFemale() Returns true if female, false if not
``pt.isFemale()``
isMale() Returns true if male, false if not
``pt.isMale()``
getReasonForVisit() Returns the patient's reason for visit (not supported for all EMRs)
``pt.getReasonForVisit() == 'PHE'``
getCppItemKeys(cppListKey) Returns a string array of the patient profile items. Available keys will vary by EMR. See Medication Reconciliation eForm for an example of Rx profile item.
``pt.getCppItemKeys('rx').length > 0``
getCppItemData(cppListKey) Returns a key-value table for a CPP item with a specified list key and item key.
``pt.getCppItemData("immu", "influenza virus vaccine")``

## ScriptUtil Functions

ScriptUtil provides miscellaneous functions that allow you to simplify your scripts and support special use-cases. ScriptUtil is bound to all script session contexts, so you can use these functions in tablet rules or within eForms (show if, make note if, etc.).

Variable(s) Description & Example Expression

sum, max, min

Returns the sum/max/min of point values in the section

``ScriptUtil.sum(section1Ref) > 10``

The number of answers matching the value or point value in the specified section

``ScriptUtil.countAnswersMatching(mySection,'other') > 0``

percentComplete

Returns a number between 0 and 100 representing the number of completed items in a section (including nested sections)

``ScriptUtil.percentComplete('nutriSTEPQs') == 100``

getKeyword

``ScriptUtil.getKeyword('@providerName') == 'John Smith'``

getResponse

``ScriptUtil.getResponse('mySmokingScreenForm','isCurrentSmoker') == 'Y'``

queueContains

(supported on Ocean Tablet only)

Returns true if the form queue (or completed forms) contains the ref passed in.

``ScriptUtil.queueContains('phq9')``

queueSize

(supported on Ocean Tablet only)

Returns the number of forms in the queue plus any forms that have already been completed.

``ScriptUtil.queueSize() == 0``

parseDate

Accepts a date string in "yyyy-mm-dd" format and returns a Javascript Date (tablet v127+)

``ScriptUtil.parseDate("2015-3-5")``

webQ

Displays sections or items for web questionnaires only, not tablets.

``ScriptUtil.isWebQ()``

walkIn

Returns true for walk-in patients (tablet v178+).

``ScriptUtil.isWalkIn()``

## Using Formula Scripting to Calculate an Average

A hidden formula item can be added to an eForm to calculate the average of certain values collected from the eForm questions.

### Simple Averages

Generating a simple average is straightforward if you can always assume a fixed number of answered questions (i.e. if you require a response to all questions).

``Simple Average = Total Value of Responses / Number of Questions``
##### Example:

If you have five questions with refs 'q1', 'q2', 'q3', 'q4', and 'q5', your formula would look like this:

``(q1.p + q2.p + q3.p + q4.p + q5.p) / 5``

However, it gets a bit trickier if you only want to count a question when it’s answered. The main difference is that you need to calculate the number of questions that are answered for the denominator.

``Average Answer = Total Value of Responses / Number of Questions Answered``

You can check if a question has been answered by looking at its literal response (.r).

q1.r == ''
q1.r == 'N'
q1.r == 'Y'

The following is JavaScript shorthand for saying "use 1 if q1.r isn’t empty; otherwise use 0"

``(q1.r != '' ? 1 : 0)``
##### Example:

Using the previous example, if "q3" was left blank, you would only want to divide by 4 when generating the average. That means you need to calculate the denominator by adding 1 for each answered question.

This is what your new formula would look like:

``(q1.p + q2.p + q3.p + q4.p + q5.p) / ((q1.r != '' ? 1 : 0) + (q2.r != '' ? 1 : 0) + (q3.r != '' ? 1 : 0) + (q4.r != '' ? 1 : 0) + (q5.r != '' ? 1 : 0))``

## Limiting the Number of Decimal Places in Formula Calculations

When developing complex formulas in Ocean eForms, you may find yourself with a large number of decimal places (e.g., 2.342456677543). In order to limit the number of decimal places, simply add ".toFixed(#)" to the end of your formula, where # is the desired number of decimal places.

#### For example:

##### Original formula:
``(( (6 - q1.p) + (6 - q2.p) + (q3.p) ) / 3)``

This formula would result in an answer such a 2.666667

##### Revised formula:
``(( (6 - q1.p) + (6 - q2.p) + (q3.p) ) / 3).toFixed(2)``

This formula would result in an answer such as 2.67

## Advanced JavaScript in Forms ("Fancy Stuff")

### Inline Functions

Sometimes, you want a "formula" or "show if" expression to do really fancy stuff. Perhaps you want to do an "if/then/else" type of expression to decide whether a section of questions resolves to level 1 or level 2. It could be a lot more complicated than that (see the probability of readmission score for an example).

You will find that adding a simple `if (x) { return y; }` won't work. For example, the following will not work:

``(ScriptUtil.sum(mySection) > 5) return 2; else return 1;``

The trick is that you need to define and execute a function inline, like this:

``function() { if (ScriptUtil.sum(mySection) > 5) return 2; else return 1; }() ``

### Technical Details

To break this this down, this part defines the function: `function() { if (ScriptUtil.sum(mySection) > 5) return 2; else return 1;}` and the `()` at the end simply runs the newly defined function.

### Date Manipulations

You can create a new Date in Javascript using the `new Date()` call, which returns the current date/time instant. You can use `new Date(2020,2,10)` to create a date for March 10, 2020 (yes, March; the month is confusingly 0-indexed, so January is month 0).

You can call `new Date().getMonth()` to get the current month (0-indexed again, so March is month 2).

To compare dates, simply subtract them to obtain the number of milliseconds in between, then divide that difference by `1000*60*60*24` to get the difference in days.

As long your script evaluates to a single expression, you can do pretty much anything that you can do with Javascript. Some advanced scripting functionality uses an inline function as described above to have a complicated multi-line algorithm wrapped in a single expression.

You can learn more about Javascript using Google (e.g. "how do I compare dates in Javascript?") or by reading a good reference book (e.g. "Javascript: The Good Parts").

## Reverse Coding in Ocean eForms

Occasionally, when developing scales using Likert-type questions, you will find yourself needing to reverse code some of the items.

For example, an item such as "I don't like working with computers" scored from 1-5 (where 1 is "strongly disagree" and 5 is "strongly agree"), should be re-coded so that the negative answer is associated with the lower score. Re-coding is especially important if the item is being used in a formula to compute a scale score.

In Ocean, your reverse coding formula would be as follows:

``New score = (max + min) - response``
##### Example:

You have provided your patient with a 3-question survey scored on a 5 point-scale. Questions 1 and 2 are reverse coded. You would like to calculate a mean score for the survey.

###### Survey Fesponses:
• Question 1 (q1.p) = 5
• Question 2 (q2.p) = 4
• Question 3 (q3.p) = 1
###### Ocean Formula:
``((6 - q1.p) + (6 - q2.p) + (q3.p)) / 3``
###### Mean Score:
``( ( 6 - 5 ) + ( 6 - 4 ) + 1 ) / 3 = 1.33``