By default, SuiteCommerce and SuiteCommerce Advanced web stores track all HTTP CRUD requests that are initiated with jQuery.ajax() and its wrappers. This means all page loads, requests to the item search API and NetSuite services, and any other customization that uses this method. Accordingly, the application will ‘know’ when data is being sent or received and can show an icon, animation or some other message indicating that it’s busy.

By default, we show a simple animation that follows the user’s mouse cursor around that looks like this:

Our default loading icon

Now, for whatever reason, you may want to customize this. For example, it is not very mobile friendly as it does not show on devices that do not have a cursor. Thus, there are two main customizations that developers are frequently asked to do:

  1. Keep the behavior but change the animation image
  2. Change the behavior, thus opening the door for more advanced customizations

If you just need to change the image that is used, then you can find the GIF we use in your site’s theme, usually called ajax-loader.gif, which is stored in the assets/img directory.

Alternatively, if you want to change the behavior then you will need to make some larger modifications. Depending on how deeply you want to go, there are two main routes you can go:

  1. The most straight-forward method is to unbind the event handlers for ajaxStart() and ajaxStop(), which are what the code uses to show/hide the icon
  2. Write your own jQuery.ajaxSetup module and override the core version with yours

I would express caution about the latter, because there are many lines of code with our own default that deal with other parts of jQuery.ajax() beyond that of the loading icon. Furthermore, overriding this module is only available to SuiteCommerce Advanced.

Therefore, we will talk about the first method.

Removing Existing Loading Indicator

The first step is to remove the existing NetSuite code for this.

The crucial parts we need to deal with are:

  1. The event handlers
  2. The element that renders the loading animation

In order to these, you will need to run the following code in a module/extension entry point file:

jQuery(document).unbind('ajaxStart', SC.loadingIndicatorShow);
jQuery(document).unbind('ajaxStop', SC.loadingIndicatorHide);
jQuery('#loadingIndicator').remove();

The loadingIndicatorShow and loadingIndicatorHide functions are the handlers we (NetSuite) use by default to show and hide the icon. By providing jQuery’s unbind() method with references to those functions, it will specifically remove those from the ajaxStart and ajaxStop events. (If you don’t provide a function or name, it will remove all handlers from those events, which is overly broad for our purposes.)

You should run these before you return the module object (ie not inside a mountToApp or initialize property) as we want them to run as soon as possible. Make sure you add jQuery as a dependency.

If you save and run this, your web store will no longer have any loading indicators.

Aside: Super Quick Workaround

If you’re not a position to add some JavaScript and just want to get rid of the GIF as soon as possible, then you can replace the icon with a single-pixel GIF. You will need to:

  1. Open an image creator / paintbox software
  2. Create an image 1x1 pixel in size (note that GIFs don’t support transparent pixels, so you should pick a color that won’t stand out, such as white)
  3. Save the image as ajax-loader.gif
  4. Go to where this file is stored in the file cabinet and replace the existing image with your new one

Note that this won’t disable any of the JavaScript associated with the loading icon, but it has the benefit of requiring no technical knowledge and takes the shortest time to do.

Adding a New Loading Indicator

After you have removed the defaults, you will need to think about what you want to replace it with. There are numerous contributions online available through licenses such as the MIT license, which allow you to use them commercially.

Alternatively, you may choose to create your own.

Whichever you choose, you will then need to bind two callbacks to jQuery’s AJAX events. Therefore, after you have defined your new indicator, your code will look something like this:

define('CustomLoadingIndicator', [
    'jQuery',
    'LoadingIndicatorLibraryFile'
], function CustomLoadingIndicator (
    jQuery,
    LoadingIndicatorLibraryFile
) {
    'use strict';

    // Remove existing loading indicator
    jQuery(document).unbind('ajaxStart', SC.loadingIndicatorShow);
    jQuery(document).unbind('ajaxStop', SC.loadingIndicatorHide);
    jQuery('#loadingIndicator').remove();

    // Dummy code to load the third-party loading indicator file
    LoadingIndicatorLibraryFile.mountToApp();

    // Code to create new event listeners
    jQuery(document)
        .ajaxStart(LoadingIndicatorLibraryFile.loadingIndicatorShow())
        .ajaxStop(LoadingIndicatorLibraryFile.loadingIndicatorHide());
});

Keep in mind that this dummy code — the exact structure or calls will depend on how your loading indicator’s code works.

LoadingIndicatorLibraryFile refers to an arbitrary file that contains your custom loading indicator code, such as those from a third-party. If you’re writing your own code, then you can just ignore that and put all of the code in the entry point file.

Creating a ‘Blocking’ Loading Indicator

Some site administrators prefer to implement loading indicators that are full-screen and prevent the user from performing actions while loading is occurring. Depending on your point of view, this can create a good or bad user experience:

  • Good: Is obvious to the user that their action is being worked on; shows on all devices, including mobile; can prevent undesirable repeated actions (eg submitting an order or other form more than once)
  • Bad: The customer must wait and cannot perform passive actions (such as browsing item lists or reading content on the current page); many concerns that it ‘addresses’ are addressed in other ways (eg validation, disabling of form buttons, etc)

The simplest form of implementing a block loading indicator is change the HTML associated with the #loadingIndicator selector. It can be used with the default or a custom loading image. Unfortunately, this HTML is within jQuery.ajaxSetup, so, to make changes, you will need to make a code-level customization.

The trick is to create a container element for your image which is positioned in the top-left of the page, full-height and full-width, and has a very high z-index value. For styling, this can be semi-transparent so it still shows the page behind it but the user cannot interact with it.

The image loads in this container, and you can use some styling to center it.

As a proof-of-concept, visit your site and use your browser’s developer tools to replace the #loadingIndicator element with the following (copy your loading icon’s path and replace it in the following snippet):

<div id="loadingIndicator" style="position: fixed; top: 0; left: 0; height: 100%; width: 100%; z-index: 9999; background-color:rgba(255, 255, 255, 0.85);"><img class="global-loading-indicator" src="path/to/your/img/ajax-loader.gif" style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%)"></div>

To implement this, you would need to inject this into your site’s DOM (like our code does) and then show/hide it accordingly.

Here is an example (with a new, exaggerated loading icon):

Other Technical Considerations

There are some additional things developers should keep in mind.

Using Third-Party Libraries

In addition to ensuring you are using third-party software in accordance with its license, you should follow our best practices on adding a third-party library to your site.

Cursor Tracking Performance

If you wish to implement cursor tracking, you will need to be wary of performance issues associated with this. We rely on the mousemove event, but you should execute on this judiciously.

For help, refer to our instance of jQuery.ajaxSetup where we introduce throttling so that the event handler is only triggered once every 50 milliseconds.

To do this, we use the throttle() method provided by Underscore. For example:

jQuery(document.body).on({
	mousemove: _.throttle(function (event) {
		// your cursor tracking code
	}, 50);
});

Behind the scenes, it creates a duplicate of the provided function/callback which fires once every x number of milliseconds. If you don’t do this, every single movement of the mouse will trigger your code and that could have serious performance issues.

Remember, ‘blocking’ loading icons don’t need cursor tracking, so don’t include it.