A Labor of Love Part Deux – Creating the A-Z Directory Module

In this post, I document the creation of the A-Z Directory module available on the Joomla Extensions Directory (JED). This is the second module I’ve developed and shared with the open-source community. I’ve documented the first one—the LinkedIn Company Updates module—so I’ll be focusing on the unique aspects of the A-Z Directory instead of rehashing Joomla’s module creation process.

The Process

Progressive Enhancement

One of my fundamental goals for this project was to implement the functionality using progressive enhancement. I started with HTML, CSS, and server-side code, and ensured the functionality worked as expected before layering on the Javascript. The Javascript uses Ajax to display the contact information without refreshing the page, providing for a nicer user experience, but not at all necessary to display the information requested by the user.

This does have the consequence of prohibiting a developer’s ability to create a template override for the output of the contact information. While the PHP rendering of the contact information is available for override, the Javascript rendering of that same output does not fall within Joomla’s MVC structure and cannot be overridden without modifying the core module code itself.

If you are a developer and want to modify the Javascript to change the display of the contact information, modify modules/mod_azdirectory/assets/modazdirectory.js.

Ajax

Joomla has pretty good documentation on how to use their com_ajax component to make Ajax requests. In the documentation, it explicitly mentions my use case—”A module that interacts with a component that you did not develop”. The A-Z Directory module gets all of its data from Joomla’s built-in Contacts component.

The Ajax request looks like this:

var request = {
'option' : 'com_ajax',
'module' : 'azdirectory',
'method' : 'getContacts',
'data' : letter,
'format' : 'json'
};
var jqxhr = jQuery.ajax({
method : 'get',
data : request,
dataType : 'json'
});

The method—getContacts—requires a function called getContactsAjax within the module’s helper.php file. It is within that function that I craft the database call and store all of the information I will need to reference within the Javascript callback that draws the contact information.

The Ajax request is contained within an azRequest function. The module is responsive—on narrower viewports, the alphabet is replaced by a <select> dropdown. Check out the demonstration and resize your browser handle to see this in action. The “click” of the alphabet letters and the “change” of the <select> calls the same azRequest function and passes the clicked or selected letter to that function.

History API

In order to enable the browser’s back/forward button support, I use the History API pushState whenever a letter is clicked or selected with the following function:

var azPush = function( letter ) {
if( window.history && history.pushState ) {
var azURL = '?lastletter=' + letter + '#modazdirectory';
history.pushState( letter, '', azURL );
}
};

The History API popState is triggered when the browser’s back/forward button is used. By passing the pushState the clicked or selected letter as the first parameter, I can get that letter within the popState listener using the event’s state and use the same azRequest function to redraw the page.

window.addEventListener('popstate', function( e ) {
if( e.state !== null ) {
azRequest( e.state );
}
});

Broken Images

I had some fun with broken image handling, inspired by a wonderful post on onbitsofco.de called Styling Broken Images. If the module is configured to display images, but an image has not been uploaded or is invalid within the Contacts component, I display this instead:

broken-image

Staying true to progressive enhancement, in PHP I used the getimagesize function, which will return an empty array if the image is broken. From there, I render the IcoMoon span to display the placeholder. On the Javascript side, the browser returns an error code, and you can trap for that error with something like the following:

jQuery( 'img.modazdirectory__image' ).on( 'error', function () {
var iconCamera = jQuery( '<span>' ).addClass( 'modazdirectory__icon-camera' );
jQuery( this ).replaceWith( iconCamera );
});

JEDChecker

Once again, the JEDChecker component proved to be invaluable before submitting my module to the JED. It alerted me to several deprecated functions I was using. Specifically, several references to JRequest::getVar needed to be replaced with JFactory::getApplication()->input.

Additional Resources