Skip to content

JavaScript Beyond the Basics

Flow Control Statements

The path that is followed when executing the JavaScript code is called the "flow". Flow control statements are used to decide which code is executed and which code is not. They can also cause certain sections of code to get executed multiple times.

Code Fragments Description
if

In the example below the id from PID-2 would only be copied into PID-4 if there is a value in PID-2.

if (StringUtils.isNotBlank(source.getNode('PID-2'))) { var value =source.getNode("PID-2"); message.setNode("PID-4", value); }
if else

In the example below if the sending facility is equal to MHS then the sending facility is set to 6343 otherwise the sending facility is set to 9384.

var facId =''; if (StringUtils.equals(source.getNode('MSH-4'), 'MHS')) {

facId = '6343';

} else {

facId = '9384';

}
?:

The ternary operator is a shorthand way of writing an if else statement. In the example below if the facility id in MSH-3 is equal to MHS then the facId variable would be set to the value of 6343 else it would be set to the value of 9384.

var facId =StringUtils.equals(source.getNode('MSH-3'), 'MHS') ? '6343' : '9384';
for

A for loop is used to execute a block of code multiple times. For example if you had an HL7 message with multiple note segments (NTE) and you wanted to perform similar actions on each segment a for loop could be used to reduce the amount of code needed.

var nteCount =source.getCount('NTE');

// The nteCount variable holds a numerical count of NTE segments.

for (var i =0; i < nteCount; i++ ) {

//code to be executed x number of times.

}

or

var nteSegs =source.getAllNodes('NTE');

//The nteSegs variable holds a string value with a list of the NTE segments found.

for (var i =0; i < nteSegs.length; i++ ) {

//code to be executed x number of times.

}

JavaScript Error Control

When creating custom code using JavaScript errors can and happens. Knowing how to handle and work with the errors can be helpful for resolving them. JavaScript has the following statements and functions for capturing and throwing errors.

Code Fragments Description
throw

The JavaScript throw statement can be used to throw an error. If the throw is executed within the try section, it is caught in the catch section (See 'Patient not found in database' error example in the try catch description below). Often times, you can catch an error and re-throw it with a more descriptive or helpful error message.

//Get patient DOB year

try {

var dobYear =message.getNode('//birthTime/@value')

.substring(0,4);

messageCache.setValue('dobYear', dobYear);

} catch (err) {

// give the user a more helpful error message

throw 'Could not find a date of birth';

}
try/catch

The try…catch statement is used to better handle errors. The code between the try and catch statements is executed and if an error occurs it jumps to the catch block.

var pid = source.getNode('PID-3');

if (StringUtils.isNotBlank(pid)) {

try {

var externalIdResult = qie.doQuery(SQL Statement to get

patients id);

if (externalIdResult.getRowCount() > 0) {

// We got a result from the query so the script now

// set that value into the message.

message.setNode('PID-3',

externalIdResult.getNode('externalid'));

} else {

throw ('Patient not found in database.');

}

} catch (err) {

// We are catching any errors that may occur with

// the database query and returning a more

// friendly error message.

if (StringUtils.containsIgnoreCase(err, "Cannot create PoolableConnectionFactory")) {

throw ('The database connection does not appear' +

'to be setup or available');

} else {

// This throws all other errors that don't

// match the PoolableConnectionFactory error.

// for example the 'Patient not found error

// in the try code block above'.

throw(err);

}

}

}

try/finally

The try/finally code block is used to ensure that a certain piece of code is executed, regardless of what happens in the try block. The code in the finally block is executed every time.

var files =['file1.txt ', 'file2.txt ', 'file3.txt ']; for (var i =0; i < files.length; i++) {

try {

var fileContents =qie.readFile(files[i]);

//... do some work with the file contents

}

finally {

//no matter what happens in the try block,

// add an inbound message

qie.addInboundMessage(files[i], files[i]); } }
try/catch/finally

The try/catch/finally statement is used to ensure that a certain piece of code is executed, regardless of what happens in the try/catch blocks. The use of the catch block is the same as in the try/catch snippet. The code in the finally block is still executed every time, just as in the try/finally code snippet.

var files =['file1.txt', 'file2.txt ', 'file3.txt ']; for (var i =0; i < files.length; i++) {

try {

var fileContents =qie.readFile(files[i]);

//... do some work with the file contents

} catch (err) {

//something went wrong reading the file and

// we'd like to log this info

qie.error("an error occurred reading " + files[i]);

} finally {

//no matter what happens in the try/catch blocks,

// add an inbound message

qie.addInboundMessage(files[i], files[i]); } }

Data Types

Sometimes it is helpful to know the object type of a variable. QIE scripts are run in Java, so the object type can either be a JavaScript object type or a Java object type. Use the JavaScript typeof key word to determine the type of a JavaScript object. The JavaScript type is one of the following:

Type Description
Number JavaScript has only one type of number. It can be written with or without decimals or using scientific (exponential) notation (i.e. 34.00, 34, 123e5, and 123e-5 are all valid JavaScript numbers)
String JavaScript strings are written with quotes. You can use single or double quotes. The String can contain quotes, as long as they do not match the quotes surrounding the string (i.e. "Qvera", 'Qvera', "He's awesome")
Boolean JavaScript Booleans can only have two values: true and false.
Object JavaScript objects are a special data type that allow any number of properties. Each of the properties of the object are written as name:value pairs, separated by commas (i.e. var problem = {icd9:"780.51", description:"Insomnia with sleep apena, unspecified"} )
null JavaScript null is a special object type that represents "nothing". If a variable is set to null, it means that it does not have a value.
undefined JavaScript undefined is another special object type that represents something that has not been defined yet. undefined and null are similar but null actually has a type of 'object', while undefined has a type of 'undefined'.

If it is a Java object the JavaScript type is 'object'. The getClass() or instanceOf keyword method can be used to determine the type of a Java object. If the value is not a Java object then the type of the variable is returned and displayed as Boolean, Number, et cetera.

Example

//get the patients id
var pid = source.getNode('PID-3');
// get the data type
var varType = typeof pid;
// if it is an object, use the Java getClass() method
if (varType === "object") {
  varType = pid.getClass();
}
// Log the output of the variable type
qie.debug("The type of myVar is: " + varType);

Output:

The type of myVar is: class java.lang.String

JavaScript Special Characters

There are certain characters that need special handling when writing JavaScript code. For example, to include a new line inside of a literal string value you can include '\n'.

Refer to the following table for all of the special characters and their representation:

Code Outputs
\ single quote
\ double quote
\ backslash
\n new line
\r carriage return
\t tab
\b backspace
\f form feed

Example

The following example concatenates three string variables together with carriage returns (\n\r) added between each value.

var string1 = "Nothing is impossible, \n\r";
var string2 = "the word itself says I'm possible! \n\r";
var string3 = "Audrey Hepburn";
var quote = string1 + string2 + string3;

The variable quote now holds the entire saying including carriage returns.

Nothing is impossible,

the word itself says I'm possible!

Audrey Hepburn

JavaScript In-Line Functions

JavaScript functions can be defined with optional parameters. The parameters are not necessary when calling the function. If a parameter is not passed when calling the function, that parameter is 'undefined'. This can be useful when writing functions that can be reused, sometimes called with the parameters provided and other times without.

Example

This function takes a parameter of 'ssn' and a boolean value of true or false to determine whether it removes or add dashes to the new ssn.

function formatSsn(ssn, includeDashes) {
  // test to see if the ssn parameter was passed in and is not
  // null
  if (ssn && StringUtils.isNotBlank(ssn)) {
    // This rest of this code will only execute if ssn is
    // provided and is not null
    // Regardless if includeDashes is true or false we will
    // remove any dashes that "may or may not" be present
    // then add dashes later if it is true else we will
    // return the ssn without dashes.
    var newSSN = StringUtils.replace(ssn, '-', '');
    // now add dashes if includeDashes is true
    if (StringUtils.equals(includeDashes, 'true')) {
      newSSN = StringUtils.substring(newSSN, 0, 3) + '-' +
      StringUtils.substring(newSSN, 3, 5) + '-' +
      StringUtils.substring(newSSN, 5, 9);
    }
    // returns the newly formatted ssn.
    return newSSN;
  }
}

// Here is how to call the function without providing a parameter.

formatSsn();

// Here is how to call the function above with a parameter.

formatSsn('111-22-3333');

After calling the formatSsn function it returns the formatted SSN. This value needs to be captured. It can then be stored in a variable or put back into the message.

var newSSN = formatSsn('111-22-3333');
or
var newSSN = formatSsn(source.getNode('PID-18'));
or
message.setNode('PID-18', formatSsn(source.getNode('PID-18')));

JavaScript Global Functions

There are some global functions provided by the JavaScript framework. These functions can always be used. Some of these functions are as follows:

Global Functions Description
isNaN()

This stands for "is not a number". Returns 'true' if the value is an illegal number

var phone ='987-6543 cell'; if (isNaN(phone)) {

// this code will execute since phone contains

// non-numeric characters

}
parseInt()

Parses a string and returns an integer. This is useful if you need to turn a string value into a number.

var bpi ='125'; if (parseInt(bpi) > 0) {

// this code will execute since bpi's integer

// value is 125

}
Number()

Converts an object to a numeric value (ie. '5' string to 5). This is another way to turn a string value into a number, but can also be used to turn other objects into a number. If the string value passed in cannot be interpreted as a number, the value with be the Global Property "NaN" (or not a number).

var age ='25'; if (Number(age) > 20) {

// this code will execute since the numeric value of

// age is 25

}
String()

Converts an object's value to a String (ie. 5 number to '5')

var weight =150; if (String(weight) ==='150') {

// this code will execute since weight's String

// value is 150

}

JavaScript Arrays

Arrays are a helpful way of storing a collection of values or objects in a single variable. To access the values in the array, simply reference their index. Think of an array as an excel spreadsheet. Where column "A" is the index reference and Column "B" holds the value, and each row is a new value in the array. JavaScript array indexes are zero-based, which means that to get the first element of the array, you use an index value of 0. To get the second element in the array, you use an index value of 1 and so forth.

Example:

Index Value
0 value1
1 value2
2 value3

Arrays can be created in the following ways:

var myArray = []; // creates an empty array
var myArray = ['value1', value2]; // creates an array with 2 values. The first with a literal value and the second using the value from a variable.

Once the array is defined, additional entries can be added to the array simply by referencing the new index. The index starts at 0 for the first entry. For example:

myArray[0] = 'value1';
myArray[1] = 'value2';
myArray[2] = 'value3'; // adds a new 3rd entry

In the following example a new "Array" object is created from the HL7 patient name field of PID-5. This same example is also demonstrated in the JavaScript Dynamic Objects (JSON) section below using a JavaScript object (JSON). The advantage of using a JSON object over an Array is the clarity of the names element when referencing them later on.

var name = []; //Creates an empty Array
// The following lines populate the Array
name[0] = source.getNode('PID-5.2');
name[1] = source.getNode('PID-5.3');
name[2] = source.getNode('PID-5.1');

The "name" Array now holds the value of:

Don,C.,Bassett

The values can now be used as follows:

message.setNode('NTE-3', name[0] + ' ' + name[1] + ' ' +
name[2]);

Output:

NTE|1||Don C. Bassett|

JavaScript Dynamic Objects

Number, String, Array and Function are all examples of a JavaScript Object. In addition to these built in object types, custom object types can be defined along with the methods and properties of the object. These custom objects can then be manipulated like any other JavaScript Object. Custom or dynamic objects can be used to store information and easily access it later on.

A Dynamic JavaScript Object can be represented in String form, which is called "JavaScript Object Notation" or JSON. The JavaScript Object can be converted to and from the JSON format.

Custom or dynamic objects can be created in the following ways:

// create empty object using a direct instance
var person = new Object();
person.first = 'Don'; // defines first as a string 'Don'
person.age = 22; // define age as the number 22
// create the object using object literals
var person = {first:'Don', age:22};
// create an empty object
var person = {};
person.first = 'Don'; // define first as a string 'Don'
person.age = 22; // define age as the number 22

In the following example a new JSON object is created from the HL7 patient name field of PID-5. This same example was demonstrated in the JavaScript Arrays section above using an array. The advantage of using a JSON object over an Array is the clarity of the element names when referencing them later on.

var name = {}; // Creates an empty JavaScript object
// The following lines populate the JavaScript object
name.first = source.getNode('PID-5.2');
name.middle = source.getNode('PID-5.3');
name.last = source.getNode('PID-5.1');

The 'name" object now holds the value of:

{
   "first": "Don",
   "middle": "C.",
   "last": "Bassett"
}

The values can now be used as follows:

message.setNode('NTE-3', name.first + ' ' + name.middle + ' ' +
name.last);

Output:

NTE|1||Don C. Bassett|

Overriding Java Methods in a Script

Because QIE runs JavaScript inside the Mozilla Rhino engine, scripts can instantiate Java classes directly. Rhino lets you override one or more methods of the Java class at the point of instantiation using a JavaScript object literal:

var instance = new MyClass() {
    myMethod: function() {
        return "MyNewValue";
    },
    myMethodWithParameter: function(parameter) {
        return "MyNewValue" + parameter;
    }
};

The override block lists each method name to replace and a JavaScript function to call instead of the underlying Java implementation. Calling instance.myMethod() from anywhere, including Java code that holds a reference to instance and invokes the method via the original signature, runs the JavaScript override.

See Overriding Java Methods in the Reference Manual for the quick syntax lookup.

Working with Strings

Java strings and JavaScript strings behave differently in a QIE script, and QIE bundles a null-safe StringUtils library to avoid the difference entirely. Both are covered in Working with Strings.