Event Selectors, Data Objects, and akt.js
When developing web applications without an organized approach to writing JavaScript, you can quickly end up with quite the mess. Inlining script tags in HTML partials may seem innocent enough—especially when a project is in its infancy. However, a few click handlers here and a dash of data-binding there can spiral out-of-control in a hurry. The appeal of inlining server-rendered arguments in function invocations becomes an afterthought. The behavioral component of your application becomes exceedingly brittle, and each subsequent change becomes a new turn in a frustrating game of Jenga.
...
<button class="btn">Go!</button>
<script>
jQuery('.btn').on('click', function(e) {
alert('Go!');
});
</script>
...
Here are a few weaknesses to this approach:
- Increased likelihood of global scope pollution
- Scattered and incoherent code
- Blocking inline scripts
–
A separate concern is the common usage of class- and id-based selectors for
wrapping DOM elements in jQuery objects. While there are certainly performance
considerations to be made when stepping away from this practice, it is worth
thinking about selection in terms of separating concerns. In the code snippet
above, the btn
class is probably serving multiple purposes: we use it as a
CSS selector to apply styles and as a DOM element selector to bind an event handler.
This type of coupling should trouble us. If at some point we decide to apply
the styles associated with the flat-btn
class—switching out the class name—we
effectively break the behavior associated with the .btn
selector.
Event Selectors & Data Objects
I’ve found that using a
separate “event selector” can be a great way to isolate responsibility and
convey behavioral meaning. This is essentially just a specific data attribute
with intention-revealing values used throughout the application. We can of
course use the data
attribute and its value as a DOM element selector, much
like we would use a class
or id
.
<button data-event-selector="btn-trigger-go">Go!</button>
...
function $(selector) {
return jQuery('[data-event-selector="' + selector + '"]');
}
var $btn = $('btn-trigger-go');
Also, in the absence of view models (a la Knockout or Angular), it helps to
have a painless way to pass data around the application. Rather than creating
separate data
attributes for each piece of information we need to process, we
can make use of something like Michael Best’s JavaScript Object Literal Parser
to parse all data from a single “data object” attribute.
<button data-event-selector="btn-trigger-go"
data-data-object="name: 'Gatsby', teams: 2">Go!</button>
...
var data = parseObjectLiteral($('btn-trigger-go').
data('eventSelector'));
akt.js
I bundled these two concepts—event selectors and data objects—into a small JavaScript library called akt.js. The README describes things fairly succinctly. Enjoy.