Loading Indicators

Loading Indicators

Indicate that the page is currently loading.

When the AJAX framework makes a request to the server, it is a good idea to display a loading indicator since the page may not update immediately. There are several approaches and standard loading indicators to make it clear when an AJAX request has been triggered and is in progress.

# Progress Bar

A prominent feature of the AJAX framework is a progress bar that is displayed on the top of the page when an AJAX request runs. The progress bar listens for an AJAX request and will appear when a request takes longer than 300ms and hides again when the request is complete.

To disable the progress bar for a request, set the data-request-progress-bar attribute to false.

<button
    data-request="onDoSomething"
    data-request-progress-bar="false">
    Do something
</button>

In JavaScript, set the progressBar option of an AJAX request to false.

oc.ajax('onSilentRequest', { progressBar: false });

To disable the progress bar globally, set the visibility style to hidden using a StyleSheet.

.oc-progress-bar {
    visibility: hidden;
}

You may display the progress bar using JavaScript using the oc.progressBar object and show / hide functions.

oc.progressBar.show();

oc.progressBar.hide();

# Loading Button

When submitting forms, users can accidentally click the button twice and cause a double submission, and this is solved using a loading button. During AJAX requests, button elements that have the data-attach-loading attribute will be disabled, and a CSS class oc-attach-loader added. This class will spawn a loading spinner on button and anchor elements using the :after CSS selector.

<a href="#"
    data-request="onDoSomething"
    data-attach-loading>
    Do Something
</a>

When a button exists inside a form that contain the oc-attach-loader attribute will display the loading indicator.

<form data-request="onSubmit">
    <button data-attach-loading>
        Submit
    </button>
</form>

Since inputs do not support the :after CSS selector, they have a new element inserted after them instead. The element is removed once the AJAX request is complete. This is useful when working with the data-track-input attribute that watches the input for changes and submits the AJAX request.

<input name="username"
    data-request="onCheckUsername"
    data-track-input
    data-attach-loading />

You can manually add the loader to a button using the oc.attachLoader object and show / hide functions passing the element selector or object as the first argument.

oc.attachLoader.show('.my-element');

oc.attachLoader.hide('.my-element');

# Toggling Elements

You can use the data-request-loading attribute to make an element visible during an AJAX request. The value is a CSS selector that uses display block and none attributes to manage the element visibility.

<button
    data-request="onPay"
    data-request-loading=".is-loading">
    Pay Now
</button>

<div style="display:none" class="is-loading">
    Processing Payment...
</div>

# Detecting Global Requests

You can detect when a global AJAX request is in progress by checking the data-ajax-progress attribute on the HTML element. Expressed in a StyleSheet as the following.

html[data-ajax-progress] {
    /* Display loading indicators */
}

The attribute is also added to form elements.

form[data-ajax-progress] {
    /* The form is loading */
}

# Targeting Specific Handlers

In some cases you may want to show a loading indicator for a specific AJAX handler event, the data-ajax-progress attribute will contain the most recent handler name, and this can be used to target a specific request.

<form>
    <button data-request="onPay">Pay Now</button>
    <button data-request="onCancel">Cancel</button>

    <div class="is-payment-loading">
        Processing Payment...
    </div>
</form>

This can be targeted using a StyleSheet attribute value selector.

.is-payment-loading {
    display: none;
}

form[data-ajax-progress=onPay] .is-payment-loading {
    display: block;
}

# Working with JavaScript

For more complex scenarios, you can hook in to the AJAX JavaScript API using the ajax:promise and ajax:always events. These events can be attached to the document, form or target elements.

formElement.addEventListener('ajax:promise', function() {
    // A new request has started
});

formElement.addEventListener('ajax:always', function() {
    // A request has ended
});

The following example will disable all inputs inside a form while the request is running.

addEventListener('ajax:promise', function(event) {
    event.target.closest('form').querySelectorAll('input').forEach(function(el) {
        el.disabled = true;
    });
});

addEventListener('ajax:always', function() {
    event.target.closest('form').querySelectorAll('input').forEach(function(el) {
        el.disabled = false;
    });
});