Skip to main content

Extending the functionality of Protocols (Steps) using OnRender and OnChange

Goals

  • Understand the difference between onRender and onChange.

  • Understand best practices for onRender and onChange.

  • Know how to write onRender and onChange functions.

Key Terms

Table 44. 

Term

Definition

onRender

Custom behavior triggered when a Protocol (Step) renders.

onChange

Custom behavior triggered when a field value changes. This includes entering an initial value.



Comparison Operators

Table 45. 

Operator

Description

==

Equal to

===

Equal value and equal type

!=

Not equal to

!===

Not equal value or not equal type

>

Greater than

<

Less than

>=

Greater than or equal to

<=

Less than or equal to



Logical Operators

Table 46. 

Operator

Description

&&

And

||

Or

!

Not



Introduction

There are front-end utility functions that extend the functionality of Protocols (Steps) using onRender and onChange.

When a Protocol renders:

  • Fields can be dynamically hidden or displayed.

  • Picklist (dropdown) options can be dynamically set.

  • Notifications can be displayed to the user.

  • In L7 LIMS and L7 Notebooks:

    • Buttons and links can be added to the Worksheet action area.

      • Buttons can record data (e.g., start and end times), print sample labels, etc.

      • Links can direct the user to a URL inside or outside of L7|ESP.

When a field value changes:

  • Data integrity can be evaluated for the field or Protocol itself if the onChange is added to the Complete field.

  • Dependent fields in the same Protocol can be hidden or displayed.

  • Dependent field values in the same Protocol can be set with a computed or static value.

  • Dependent picklist (dropdown) options in the same Protocol can be dynamically set.

  • Notifications can be displayed to the user.

  • If the value is assigned to the first Sample (row) in the Worksheet:

    • The same value can be assigned to the remaining Samples (see below – autofill column data).

      • This accommodates bulk data entry, and allows the user to edit individual values when necessary.

Best Practices

Reusable functions should be written as invokables that get called from an onRender or onChange.

// Reusable function to autofill column data when the first row is initially changed.  
// col: ID of the column (field) triggering the onChange. 
function autofill_column(api, col, newValue) {
  if (row === 0 && newValue !== null) {
    for (let i = 0; i < api.getSampleCount(); i++) {
      if (api.getDataAt(i, col) == null || api.getDataAt(i, col) == '') {
        api.setDataAt(i, col, `${newValue}`)
      }
    }
  }
}

// This function is then called from an onChange.
autofill_column(api, 'Field ID', newValue)

Use switch statements for multiple if/else statements.

  • The interpreter checks each case against the value of the expression. If no match is found, the default condition will be used.

  • The break statements indicate the end of each case. If they are omitted, the interpreter will not stop when a match is found.

let expression = api.getDataAt()
switch (expression) {
  case 1: 
    statement(s)
    break; 
 case 2: 
    statement(s)
    break;
 ...
 case n: 
   statement(s)
   break; 
 default: 
   statement(s)
}

For the best performance:

  • Be mindful of functions that trigger API calls.

    • These calls can be made for each individual Sample in the Worksheet (not recommended), or as a single unit of operation when the Worksheet is created or saved (recommended).

    • saveSheet() is a common culprit.

  • Put asynchronous calls behind buttons, display a loading indicator, and disable the button until the call is completed.

Note

The following functions are documented in a LIMS context, but unless specified, are also supported in L7 MES and L7 Notebooks.

The full list of functions can be found here.

Warning

hideColumns() and showColumns() must reference fields by their display name, but the other utility functions support referencing fields by their ID. This is preferred as display names change.

Front-End Utility Functions for OnRender and OnChange

getDataAt(rowIndexOrSampleName, columnIndexOrHeaderName)

Retrieve a field value for a given row (Sample) in the Worksheet.

Parameters:

  • rowIndexOrSampleName (str|num) – the index (untransposed) or Sample name of the desired row.

  • columnIndexOrHeaderName (str|num) – the index (untransposed) or header (field) name of the desired column.

Note

Use getSharedDataAt(sharedColumnIndexOrHeaderName) for shared Protocol fields.

Examples:

// Retrieve a field value for a single row in the Worksheet (onChange).
let field = api.getDataAt(row, 'Field ID')

// Retrieve a field value for the first row in the Worksheet (onChange and onRender).
// This should be used when grouping by ALL Entities in the Worksheet. 
let field = api.getDataAt(0, 'Field ID')

// Retrieve a field value for each row in the Worksheet (onRender).
for (let i = 0; i < api.getSampleCount(); i++) {
  let field = api.getDataAt(i, 'Field ID')
}

Note

OnRender functions are evaluated before the user interacts with the Worksheet, and must evaluate a specific row or each row in the sheet.

Boolean (checkbox) values need to be converted to strings.

let field = api.getDataAt(row, 'Field ID').toString().toLowerCase()
  • toLowerCase ensures the compared values are in the same case.

setDataAt(rowIndexOrSampleName, columnIndexOrHeaderName, value)

Set a field value for a given row (Sample) in the Worksheet.

Parameters:

  • rowIndexOrSampleName (str|num) – the index (untransposed) or Sample name of the desired row.

  • columnIndexOrHeaderName (str|num) – the index (untransposed) or header (field) name of the desired column.

  • value - the value to set.

Note

Use setSharedDataAt(sharedColumnIndexOrHeaderName, value) for shared Protocol fields.

Example:

For mathematical operations, parameters need to be converted (parseFloat) to numeric values.

let mass = api.getDataAt(row, 'Input Mass')
let conc = api.getDataAt(row, 'Sample Concentration (ng/uL)')
let sam_vol = api.getDataAt(row, 'Sample Volume (uL)')
let dil_vol = parseFloat(mass) / parseFloat(conc)
let wat_vol = 56 - parseFloat(dil_vol)
api.setDataAt(row, 'Sample Input Volume (uL)', dil_vol.toFixed(1))
api.setDataAt(row, 'Water Volume (uL)', wat_vol.toFixed(1))
  • toFixed() sets the number of decimal places.

When setting a field back to its default value (including null), only trigger the onChange when there is a subsequent newValue.

if (!newValue) {
  return
}

// For checkbox fields, including Complete. 
if (newValue.toString().toLowerCase() === 'false') {
  return
}
  • Conditions should use newValue to reference the value of the current field.

setDropdownSource(rowIndex, columnIndexOrHeaderName, source)

Set a picklist (dropdown) field's options.

Parameters:

  • rowIndex (num) – the index of the desired row.

  • columnIndexOrHeaderName (str|num) – the index or header (field) name of the desired column.

  • source (array<str>) – the picklist (dropdown) options.

Examples:

// Set the dropdown options for a single row in the Worksheet (onChange).
if(newValue === 'X') {
  api.setDropdownSource(row, 'Field ID', ['Option 1', 'Option 2', 'Option 3'])
}

// Set the dropdown options for the first row in the Worksheet (onChange and onRender).
// This should be used when grouping by ALL Entities in the Worksheet.
let field = api.getDataAt(i, 'Field ID')
if(field === 'X') {
  api.setDropdownSource(0, 'Field ID', ['Option 1', 'Option 2', 'Option 3'])
}

// Set the dropdown options for each row in the Worksheet (onRender).
for (let i = 0; i < api.getSampleCount(); i++) {
  let field = api.getDataAt(i, 'Field ID')
  if(field === 'X') {
    api.setDropdownSource(i, 'Field ID', ['Option 1', 'Option 2', 'Option 3'])
  }
}

hideColumns(headerNamesOrIndices)

showColumns(headerNamesOrIndices)

Hide or display columns (fields) in the Worksheet.

Warning

Shared Protocol fields do not support these two (2) functions, but a custom function can be created to hide or display these fields.

Parameters:

  • headerNamesOrIndices (array<str>|array<num>) – array of header (field) names or indices (untransposed) to show.

Example included with the next utility function.

showNotification(message, category, title)

Show a toast notification in the bottom-right corner of the screen.

Parameters:

  • message (str) – the message in the toast notification.

  • category (str) – error, warning, success, or information.

  • title (str) – the title of the toast notification.

Example:

if (newValue === 'Other') {
  api.showColumns(['Explanation'])
  api.showNotification('Please provide an explanation.', 'information')
} else 
  api.hideColumns(['Explanation'])
}

addProtocolLink(name, target, url)

Add a link to the Worksheet action area.

Warning

This function is not supported in L7 MES.

Parameters:

  • name (str) – the name of the link.

  • target (str) – '_blank' opens the link in a new web browser tab.

  • url (str) – the url for the link.

Example:

api.addProtocolLink({
  name: 'L7 University',
  target: '_blank',
  url: 'https://university.l7informatics.com'
})