Have you ever wanted to display a loading popup to the user while your script did things behind the scenes? Today, we want to help you make that idea a reality.
The Great Dilemma
It is notoriously difficult to display any kind of loading screen/popup in NetSuite. SuiteScript developers approach this problem with various workarounds. For example, perhaps a script can be so efficient that a loading popup is unnecessary. Or perhaps the user can redirect to a SuiteLet that shows a loading screen while the automation finishes in a scheduled script (I don’t necessarily recommend this!). But sooner or later, these workarounds will not be adequate. Too many scheduled scripts, for example, might lead to significant time delays in the system. Also, not every automation can be succinct. In some situations a loading popup is ideal.
We tried out all the possibilities we can think of to overcome the hurdle of the loading popup. The window.alert()
popup will stop any automations from continuing until the popup is closed. (So that won’t work.) The SuiteScript dialog module also suffers from a similarly unusable fate.
We need to try something more custom. Something perhaps a bit more creative than usual.
A Creative Solution
Assuming you are automating something in a User Event or Client Script, I will show you step by step how to create a basic loading dialog that looks something like this:
In this example, when we click the “Refresh Rates,” a Client Script updates all the rates for each item. Because there were several factors to consider in recalculating the rates, the automation was sometimes taking longer than a few seconds to complete. Experiencing this automation time without any feedback on the purpose for the delay may confuse the user. Consequently, this was a great situation for a custom loading dialog.
Note:
The SuiteScript API does not support this customization; rather, we must manipulate the DOM in order to accomplish it. This customization is relatively safe, however, as it is adding custom HTML to the DOM with a custom field. If NetSuite ever modifies the nature of the DOM, there shouldn’t be significant danger with this method. But if something ever causes your script to not function properly, NetSuite will not be held responsible for this unofficial customization technique.
Step 1: Create a New HTML File
We will need to use jQuery to create this loading dialog. The jQuery library makes it simple to reference HTML and CSS and modify it. It also includes a versatile dialog template that we can use to make our loading popup.
Create a new HTML/HTM file. Within that file, paste the following code:
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script defer src="https://use.fontawesome.com/releases/v5.0.4/js/all.js"></script>
<div id="_loading_dialog" title="Loading dialog"></div>
You can also add <style>
tags to adjust how the dialog looks. For example, this will center the title in the dialog:
<style type="text/css">
.ui-dialog .ui-dialog-title {
text-align: center;
width: 100%;
}
</style>
This new HTML file pulls in all the basic libraries that we need to create a nice dialog.
Give your file an appropriate name and upload it to NetSuite.
Step 2: Create a Custom Field to Hold HTML
In a beforeLoad function, we will need to create a custom field in our script. This field will always add on to the web page when a user loads, but no sign of the field will be visible to the user, since the HTML contents are not user-facing.
const dialogHtmlField = context.form.addField({
id: 'custpage_jqueryui_loading_dialog',
type: 'inlinehtml',
label: 'Dialog HTML Field'
});
dialogHtmlField.defaultValue = file.load({
id: 'SuiteScripts/[whatever your path to HTML file is]'
}).getContents();
This will add the field to the form (for both view and edit mode). This field must be ‘inlinehtml’ so we can store the value of our HTML file within the field. We store the HTML file in this field by loading the HTML file and assigning it as the field’s default value. This way, our script can access it later on.
Step 3: Create the Dialog
It is likely that you already have some kind of button that will initiate the automation. If that is the case, then you will need to create the dialog in a Client script that is called when the button is clicked (clientScriptModulePath, etc.).
So at the entry point of that Client script which initiates the automation, we will create a dialog using jQuery. You may think that jQuery needs to be imported to the file, but the script will natively have access to jQuery within the NetSuite environment—so no need to import.
function handleButtonClick() {
jQuery('#_loading_dialog').attr('title', 'Running Automation');
jQuery('#_loading_dialog').html(
`<div style="text-align: center; font-style: italic;">Please wait.</div>
<br><br>
<div style="text-align: center; width:100%;">
<i class="fas fa-cog fa-spin" data-fa-transform="grow-18"></i>
</div>`
);
jQuery('#_loading_dialog').dialog({
modal: true,
width: 400,
height: 160,
resizable: false,
closeOnEscape: false,
position: { my: "top", at: "top+160", of: '#main_form' },
open: function (evt, ui) {
// jQuery(".ui-dialog-titlebar-close").hide();
setTimeout(runAutomation, 100);
}
});
}
This is probably a lot to take in. So let’s take this one piece at a time.
jQuery('#_loading_dialog')
selects the div you created at the bottom of your HTML file.- After that div is selected, we add attributes, HTML, and more to the div to convert it into a nice dialog.
jQuery('#_loading_dialog').dialog()
uses the jQuery library to really take the dialog to the next level.- Feel free to tweak these settings to fit your use case. The line that is commented out (
jQuery(".ui-dialog-titlebar-close").hide()
) will remove the ‘X’ button to close the dialog. It’s up to you if you would like this. - You can read more about all the settings for the dialog here.
- Feel free to tweak these settings to fit your use case. The line that is commented out (
- The “
setTimeout(runAutomation, 100)
” line near the bottom is absolutely key. The native JavaScript function, “setTimeout()
,” forces the code to run synchronously. The custom imaginary function, “runAutomation
,” is where the rest of your code will be. If you need to pass parameters to this function, you can do this instead: “setTimeout(function() { runAutomation(context) }, 100)
.”
Step 3: Terminate the Loading Dialog
The easiest way to close the dialog when your script finishes running (or if there is a failure) is this command:
jQuery('#_loading_dialog').dialog('destroy');
This will immediately terminate the dialog.
After setting up your code (and perhaps with a little bit of debugging as usual
Conclusion
This is one of the most technical posts we’ve done, but we sincerely hope you find this helpful. So many things can be done in NetSuite through jQuery to improve the user experience. If you find this blog helpful or have any questions, let us know in the comments! And if you haven’t yet subscribed to our email list, feel free to sign up below for our weekly SuiteScript development tutorials.
Great write up. Have 1 small issue. The spinner stops spinning once the setTimeout expires.
My code adds about 20 line items to a salesorder and does some custom calculations. All this take about 30 seconds so your pop up is great!
I have my set up as follows:
open: function (evt, ui) { setTimeout(function(){
#my code is here#
jQuery(‘#_loading_dialog’).dialog(‘destroy’);
}, 3000); }