Unobtrusive JavaScript

Friday I learned a bit more about some frameworks work under the hood using a pattern called “unobtrusive JavaScript”. Some backstory:

I wanted to add a pop-up that would appear when users tried to delete a query or a filter they were building in our VAT (Visual Analysis Tool). The popup would make them confirm they really wanted to delete it. Bootstrap’s “modal” would work perfect for this. That’s the thing that makes the whole screen go dark and then a panel fades in, floating in the center of the screen. The panel has some text and usually two buttons, one to cancel, and one to confirm. I figured because we were already using Bootstrap’s CSS classes to style the VAT, using things like the modal would be trivial. Yup. It wasn’t.

The Bootstrap modal relies on JavaScript to pull off its functionality. It’s wired up to the DOM using the Bootstrap JavaScript code they provide. And because our VAT uses React, we can’t safely shove those two JavaScript frameworks together without undefined behavior. My modal where I simply added the classes to the HTML elements didn’t work. The solution to my problem was to use bootstrap-react, a library where they re-created the Bootstrap components that used JavaScript (and jQuery) to interact with the DOM as React components, which interact with React’s virtual DOM the React way. It’s safe, and, in the context of a React app, it Just Works™.

So what exactly is unobtrusive JavaScript? Long story short, it’s when JavaScript is used to manipulate the DOM and define events without the HTML element having to be explicitly linked to the JavaScript. It’s unobtrusive because from the perspective of the HTML coder, there isn’t even any JavaScript involved. Here’s an example with a button that changes its text to “hello” when it’s clicked:

Without unobtrusive JavaScript, we define a JavaScript function that changes the HTML of the element it was fired on.

function changeToHello(event) {
// “event.target” is the HTML element that triggered this function
event.target.innerHTML = ‘Hello’;
}

Then, we use the onclick event handler of the button to link it to our function, which is now an event handler.

<button onclick=”changeToHello(event)”>Click me!</button>

Now with unobtrusive JavaScript, we use a CSS class (or it could be an id, etc).

<button class=”btn-hello”>Click me!</button>

Then, in the JavaScript, search through the DOM for elements with that class, and add event handlers to them. This code goes *after* the body, because the elements must be present on the DOM at the time the code runs, and the elements won’t be on the DOM until after the body.

// No function definition, just run code
for (element of document.getElementsByClassName(‘btn-hello’)) {
element.addEventListener(‘click’, event => {
event.target.innerHTML = ‘Hello’;
});
}

Looks complicated right? Why not just use the onclick HTML attribute? Because we’ve now made things more loosely coupled. We can choose to make something use this behavior by adding the “btn-hello” class. Want more than one click type behavior? No need to make a master onclick function that calls multiple functions. Just add, for example “btn-hello btn-goodbye” to the classes of the element.

This is exactly how Bootstrap implements modals and tabs and all their fancy things that react to users. You add a CSS class, but that’s not just using a stylesheet. It’s tapping into a huge number of event listeners and handlers that the Bootstrap team has created. They might even change them in the future. But you won’t need to worry about what events to tie to your elements. You just add “btn-hello” and call it a day.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s