Custom JavaScript columns
Guide to creating custom JavaScript columns in NIM for data transformation, including best practices and error handling.
Create a custom JavaScript column to compose a new column based on transformations of other columns. This is possible in both Data tables and Filters.
To get started, Create a JavaScript system column or Create a JavaScript filter column.
Custom JavaScript columns support Vault queries and Variable queries.
Scripted columns can be added as additional columns to a filter's results. They can also be added directly to any system table.
To determine the best place to create a scripted column there are a few things to consider:
Will this value be used multiple times or will it impact multiple layers/entities in NIM?
E.g. All of the values in the FirstName column have trailing spaces: Trimming this value will need to happen in the filters and also in the name gen.
Can the resultant value be determined solely from the data in a single table or do I need data from other joined in tables?
E.g. The OU path for a user is based on their grade level and their building name: If Grade Level and Building Name are not available in the same table, this is not a good candidate to be generated in the system table.
There are two situations where fields that you're evaluating in a Scripted Column may throw errors:
The value in the table is simply blank
Not all user objects in AD will have a description specified
See more on Nullish Coalescing
The value is coming from an "any-none" join in your filter
Not every user record in the HRMS/SIS may have an AD account
See more on Testing for Undefined
A simple way to catch errors in your scripts is to wrap the issue code in a try/catch block
let foo = 'bar'; //default value try { foo = Users['description'].toLowerCase(); } catch(e) { }
This method can become messy and difficult to understand in more complex scenarios.
The Nullish-Coalescing (see example #1 above) operator can be used to get the variable value or a default value if the variable value is empty:
let foo = (Users['description'] ?? 'bar').toLowerCase();
In the case of example #2 above, we also want to check if the table/collection object is undefined. This is a good method to use regardless of if the table is expected to be null or not.
Snippet 1: Check for undefined via TypeOf
let foo = (typeof Users_01 !== 'undefined') ? Users_01['description'] : 'bar';let foo = (typeof Users_01 !== 'undefined') ? Users_01['description'] : 'bar';
Snippet 2: Check for undefined via direct comparison
let foo = (Users_01 !== undefined) ? Users_01['description'] : 'bar';
The two methods can be combined - the first check to ensure that the table has a record. If the record does exist, then also handle the situation where the field could be empty:
let foo = (typeof Users_01 !== 'undefined') ? (Users_01['description'] ?? 'foobar') : 'bar';
Here is a real world example of this
let result = ''; let LocationAssignment = (typeof AssignConfigEmployeeLocation !== 'undefined') ? (AssignConfigEmployeeLocation['LocationName'] ?? '') : null; let Location = (typeof ConfigEmployeeLocation !== 'undefined') ? (ConfigEmployeeLocation['LocationName'] ?? '') : null; let WorkLocationAssignment = (typeof di96_pcassign_export !== 'undefined') ? (di96_pcassign_export['work_location_name'] ?? '') : null let WorkLocation = (typeof di96_perpay_export !== 'undefined') ? (di96_perpay_export['work_loc1_name'] ?? '') : null if(LocationAssignment != null) { result = LocationAssignment } else { if(Location != null) { result = Location; } } if(result === null || result.length < 1) { if(WorkLocationAssignment != null) { result = WorkLocationAssignment } else { if(WorkLocation != null) { result = WorkLocation } } } return result
String interpolation offers a way to define a string structure with variable placeholders and implicitly convert the value of the expression/variable to a string value. This is the recommended method of building strings.
See more on Template Literals
Tip
Template strings are enclosed in the tick character ( ` ).
// String concatenation return "Student @ " + Students['BldName'] + " | " + Students['Grade'].toString() + "."; // Templated strings return `Student @ ${Students['BldName']} | ${Students['Grade']}.`;return `Student @ ${Students['BldName']} | ${Students['Grade']}.`;
The placeholders ("${...}") in the template string can contain full expressions:
return `Grade ${Students['Grade'].slice(-2)}`;