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:
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
.