Loading modules into Client script called from a custom button

2.2k views Asked by At

I've got some code in a javascript AMD module. If I create a ClientScript which references it and deploy it, the code runs fine when called from the ClientScript event. But if I call the exact same function from a custom button click event, it bombs with an Unexpected error inside require.js (see the end of the post for console outputs).

Here's the ClientScript code:

/**
 * @NApiVersion 2.0
 * @NScriptType ClientScript
 * @NModuleScope public
 */

'use strict'
require.config({
    paths: {
        'iceUtil': 'SuiteScripts/ieCommon/iceUtil'
    }
});

define(['N/log', 'iceUtil'], function (https, iceUtil) {
    function calculateConfigurations() {
        console.log('calculateConfigurations: before native log call');
        log.debug({
            title: 'calculateConfigurations',
            details: 'nothing'
        })

        console.log('calculateConfigurations: before iceUtil log call');
        iceUtil.logDebug('calculateConfigurations - iceUtil log', 
            'nothing');
    }

    function fieldChanged() {
        iceUtil.logDebug('pageInit', 'begining client event');
        calculateConfigurations();
        iceUtil.logDebug('pageInit', 'ending client event');
    }

    return {
        calculateConfigurations: calculateConfigurations
        , fieldChanged: fieldChanged
    }
});

iceUtil.js really just wraps the native NetSuite log functionality.

This works fine and all logs show when called from the fieldChanged event firing.

But if I wire it up to a custom button, using the following code, only the first console.log('recordId: ' + recordId); call runs. The first call to iceUtil.logDebug bombs.

Here's the code which wires up the button:

/**
 * @NApiVersion 2.x
 * @NScriptType UserEventScript
 */
define(["N/log", "../ieCommon/iceUtil"], function (log, iceUtil) {

    function addCalcConfigsButton(context) {
        if(context.type==context.UserEventType.EDIT) {
            context.form.clientScriptFileId = 6222;
            //context.form.clientScriptModulePath = 'SuiteScripts/ieOppMetrics/clientCalculateConfigurations.js'; // This also works
            context.form.addButton(
                {
                    id : 'custpage_buttonid',
                    label : 'Calculate Configurations',
                    functionName : 'calculateConfigurations'
                }
            );
            iceUtil.logDebug("addCalcConfigButton - iceUtil log", 
                "Button added.");

            log.debug({
                title: 'addCalcConfigButton - native log',
                details: 'Button added.'
            });
        } 
    }

    return {
        beforeLoad : addCalcConfigsButton
    };
});

Here's the console output from this code when it's called from the fieldChanged event and works (the log messages also show in the NS Execution Log):

[Log] calculateConfigurations: before native log call
[Log] calculateConfigurations: before iceUtil log call

Here's the console output from pressing the button and fails (there are no log messages in the NS Execution Log):

[Log] calculateConfigurations: before native log call
[Error] UNEXPECTED_ERROR: Unexpected Error
    onError (bootstrap.js:150)
    onError (NsRequire.js:645)
    check (NsRequire.js:994)
    enable (NsRequire.js:1251)
    init (NsRequire.js:882)
    (anonymous function) (NsRequire.js:1547)
4

There are 4 answers

0
josh On BEST ANSWER

It turns out it wasn't a module loading problem at all; it was a problem in the N/log code specifically and the JS environment when getting called from the different places (NS client event vs. arbitrary JS function from a custom button).

When log.debug() is being called from the button, the JS environment has the following variables defined and with values: NLScriptIdForLogging and NLDeploymentIdForLogging, but these were not defined when log.debug() was successfully called from the NS client event.

If you run the following before calling log.debug(), it will run successfully from the button code:

delete NLScriptIdForLogging;
delete NLDeploymentIdForLogging;

I'm not sure what these are trying to do, so I'm just checking for them and skipping the log.debug() call (or routing it to the JS console if it's there).

This seems like a NS bug. Does anyone know how I can report it?

1
skylize On

"The first call to iceUtil.logDebug bombs." This is incredibly vague. Post the actual Error output (most importantly the main error and the first line in the stack trace that references your own code) to give people some hints where in your code to look for your bug.

Even without the actual error, I'd say this line looks incredibly suspicious:

functionName : 'calculateConfigurations(' + context.newRecord.id + ')'

I don't know what the underlying code is that processes your call to context.form.addButton, but I suspect from the property name functionName that the only valid value to give it is a [String] containing the name of a function within the scope of context.

Instead you are trying very hard to do some sort of dynamic function creation that probably has zero meaning to the addButton() method you are calling.

Where did context.form.addButton come from? It is not native js and has no obvious reference from your code example. Is that method provided by a library you haven't mentioned?

0
Todd Grimm On

You are likely having an issue due to the update to the require Object Configuration in NetSuite. It would be a bit much to type out so please just refer to the NetSuite documentation here for the details. If that does not give enough context for your situation refer to the 2017.2 release notes, pages 67 and 68. Hope this helps.

2
erictgrubaugh On

The functionName property of addButton is only expecting the name of the function. I don't believe you can invoke the function and pass parameters like that.

Your click handler will need to read the ID of the current record either from the context or by using the N/currentRecord module from NetSuite.