Custom AJAX loading icon
James Williams
There's nothing like Drupal's stock AJAX spinner (this: Drupal's default blue loading throbber graphic) to make you notice that a site's design hasn't been fully customised. The code from my previous article showing how to fetch a link over AJAX to open in a Foundation reveal popup would suffer from this without some further customisation. After clicking the 'Enquire' button, a loading icon of some kind is needed whilst the linked content is fetched. By default, Drupal just sticks that blue 'throbber' next to the link, but that looks totally out of place. Our client's site uses a loading graphic that feels much more appropriate in style and placement, but my point is that you can set up your own bespoke version. Since it's Christmas, let's add some festive fun! Here's a quick video showing what I'll take you through making:
A few things are needed:
- Create a javascript method that will add a custom progress indicator
- Ensure the javascript file containing the method is included on the page
- Set a custom attribute on the link that will trigger the AJAX
- Override Drupal core's javascript method that adds the standard progress throbber, to respect that custom attribute
There are many ways to achieve points 1 and 2. Usually, you would define a library and add it with #attached
. But I decided I wanted to treat my work as if it were part of Drupal's core AJAX library itself, rather than something to add separately. So I implemented hook_library_info_alter()
in my theme's main .theme
file:
/**
* Implements hook_library_info_alter().
*/
function MYTHEME_library_info_alter(&$libraries, $extension) {
// Add our own extension to drupal.ajax, which is aware of the page markup so
// can add AJAX progress loaders in the page.
if ($extension == 'core' && isset($libraries['drupal.ajax'])) {
$libraries['drupal.ajax']['js']['/' . drupal_get_path('theme', 'MYTHEME') . '/js/ajax-overrides.js'] = [];
}
}
My ajax-overrides.js
file contains this:
(function ($, window, Drupal, drupalSettings) {
/**
* Creates a new Snowman progress indicator, which really is full screen.
*/
Drupal.Ajax.prototype.setProgressIndicatorSnowman = function () {
this.progress.element = $('<div class="ajax-progress ajax-progress-fullscreen ajax-progress-snowman"> </div>');
// My theme has a wrapping element that will match #main.
$('#main').append(this.progress.element);
};
})(jQuery, window, Drupal, drupalSettings);
My theme happens to then style .ajax-progress-snowman
appropriately, to show a lovely snowman in the middle of the page, rather than a tiny blue spinner next to the link that triggered the AJAX. Given that the styling of the default spinner happens to make links & lines jump around, I've got the ajax-progress-fullscreen
class in there, to be more like the 'full screen' graphic that the Views UI uses, and avoid the need to add too much more styling myself.
Part 3, adding a custom attribute to specify that our AJAX link should use a Snowman animation, is easily achieved. I've already added the 'data-dialog-type
' attribute to my link, so now I just add a 'data-progress-type
' attribute, with a value of 'snowman
'. I want this to work similarly to the $element[#ajax]['progress']['type']
property that can be set on form elements that use AJAX. Since that only gets applied to form elements, not arbitrary links using the 'use-ajax
' class, we have to do the work to pick this up ourselves.
So this is the last part. Back in my ajax-overrides.js file, I've added this snippet to override the standard 'throbber' progress type that AJAX links would otherwise always use. It falls back to Drupal's original method when the progress type isn't specified in a 'data-progress-type
' attribute.
// Override the progress throbber, to actually use a different progress style
// if the element had something specified.
var originalThrobber = Drupal.Ajax.prototype.setProgressIndicatorThrobber;
Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
var $target = $(this.element);
var progress = $target.data('progressType') || 'throbber';
if (progress === 'throbber') {
originalThrobber.call(this);
}
else {
var progressIndicatorMethod = 'setProgressIndicator' + progress.slice(0, 1).toUpperCase() + progress.slice(1).toLowerCase();
if (progressIndicatorMethod in this && typeof this[progressIndicatorMethod] === 'function') {
this[progressIndicatorMethod].call(this);
}
}
};
So there you have it - not only can you launch beautiful Foundation Reveal popups from links that fetch content via AJAX, you can now avoid Drupal's little blue throbber animation. If it's an excuse to spread some cheer at Christmas, I'll take it.
Happy Christmas everyone!