Transformer script failed to be invoked time to time

I created a transformer named sharedUtils with following script:
function addRowPVP(table, tableState, columns) {
let result = tableState.value;
return result;
}

function deleteRow(table, tableState) {
// do something

}

// Export the functions
return {
deleteRow,
addRowPVP
};

For a button (Add Property), its Click event just does the following Run Script:
sharedUtils.value.addRow(tableAlertProperty, tableAlertPropertyState);

For a button (Delte Property), its Click event just does the following Run Script:
sharedUtils.value.deleteRow(tableAlertProperty, tableAlertPropertyState);

Problem: It works well; but after some time, retools reports the error:
Error:Cannot read properties of null (reading 'addRowPVP')
buttonAddAlertProperty
in run script, line 1(buttonAddAlertProperty)
in buttonAddAlertProperty click event handler(buttonAddAlertProperty)
from user interaction

Actually I did not change the transformer script and the button's script. I had to duplicate the script as a new script, delete the current sharedUtils, and then rename the new script as sharedUtils. It works well again.
However, after several hours, the same problem happened.

I tried the backup app, and found that

  1. when the script worked well, if I tried to input sharedUtils in the console, retools reports: Failed to execute 'postMessage' on 'Window':
  2. when the script failed to be invoked, if I tried to input sharedUtils in the console, retools reports that it is an object and its value is null.


1 Like

Hi @Jingwei_Cai, what if we define these functions on the Preloaded JS tab?

Thanks for your suggestion, I will try Preloaded JS later.
Just curious, why my transformer sharedUtils can not work?

And I already found a workaround solution, wihch looks not so elegant but good enough.

  1. Modify sharedUtils as a JS Query

  2. Define a triggerFunction parameter as function name, and then distribute the invoking request

  3. Use sharedUtils with following code:
    sharedFunctionTableEditor.trigger({
    additionalScope: {
    triggerFunction: 'addRowAlertThreshold',
    },
    });

  4. Following is code snippet of shartedUtils

function addRow(table, tableState, columns, values = null) {
..................

return result;
}

function deleteRow(table, tableState) {
return deleteRowByDataIndex(table, tableState, table.selectedDataIndex);
}

// add a property or virtual property
function addRowAlertThreshold() {
// schema
const columns = [
"line_id",
"id",
"threshold_type",
];
return addRow(tableAlertThresholds, tableAlertThresholdsState, columns);
}

// delete one row from property or virtual property
function deleteRowAlertThreshold() {
deleteRow(tableAlertThresholds, tableAlertThresholdsState);

}

////////////////////////////////////////////////////
console.log(triggerFunction);
switch (triggerFunction) {
case 'addRowAlertThreshold':
addRowAlertThreshold();
break;
case 'deleteRowAlertThreshold':
deleteRowAlertThreshold();
break;
case 'blabla':
// another function call
break;
default:
console.log("sharedFunctionTableEditor() triggerFunction not found: " + triggerFunction);
return false;
}

return true;

It may be a limitation with Transformers. Their purpose is to transform data, like filter an array of elements returned by a query, or map over it and make some changes with the purpose of rendering the output on a component. Here are some examples.

The part of the doc that says "You can use use JavaScript libraries and utility methods" contains a misleading link for utility methods (and an extra 'use,' clearly).

Here is our Utils JS library it's referencing:

For more complex JS in general, JS queries are definitely the way to go, and for reusable functions to use within an App: Preload custom JavaScript for apps | Retool Docs

A JS query is a great alternative, the only tradeoff is that every time we run it, we are defining the functions again. But unless we are defining a ton of functions in one JS query, we're not causing a considerable impact on memory in the great scheme of things.