Snook.ca

Going Simple with JavaScript

I was making a change to a page that needed to pull from a remote API and make changes to various parts of the page. Sounds like the time to pull out jQuery and Ajax, doesn't it? Instead, I just used old fashioned JavaScript. Actually, I used new fashioned JavaScript.

Browsers haven't stood still in the advent of libraries and frameworks. As a result, we can take advantage of those features when we need to bake in a little extra.

Some JSONP

The first step was to get the JSONP call executing. This is generally straightforward: embed a script tag into the page. The script will run a function that you've defined on your page.

When the script runs, it'll pass the data into the formatCurrency function. Excellent.

Once the data is in the function, I needed to grab all the elements of a particular type and make changes based on those.

querySelectorAll

The querySelectorAll method will grab all elements that match a particular selector—similar to jQuery. It's limited to selectors that the browser understands, which is definitely less than what jQuery can do. Sometimes a chisel will do in place of a sledgehammer.

The querySelectorAll method works in IE8 and up and all of the other popular browsers, too. I also wrapped my entire block of code to check if the browser supports this method before doing anything.

As you can see in the example, all I'm looking for is every element that has a class of price. I could've used getElementsByClassName but that's not supported in IE8, whereas querySelectorAll is. So far, so good.

After that, it was just a matter of getting an attribute, making some changes and then re-inserting it into the DOM using innerHTML. Easy peasy.

Progressive Enhancement

But what of users who don't support this new fandangled functionality? It'll be the same as those who don't support JavaScript. In my case, it meant that users will see just Canadian pricing instead of converting it into their local currency.

That's a total of 628 bytes. No JavaScript libraries or frameworks required. That could be minified to 469 bytes. A far cry from the 91,000 bytes needed just to get jQuery on the page.

Take it easy

"Just use jQuery" might be the go-to phrase but, thankfully, you don't always need that much code to solve a simple problem. Pages are getting bigger and bigger. It's nice to know that we don't always have to use large resources to accomplish a small goal.

Does the script mean, that even though no one wants to convert prizes you still pull the json-data on every page-load? This would be the kind of functionality I would do on the server-side with caching and stuff. Especially if I want to sell products outside Canada.

Last but not least: I agree with your last two paragraphs but would add that even though jQuery is a heavy stone to kill a small bird, it usually kills a lot of birds at the same time.

@KMB: I want the prices to show the approximate price in the local currency. I surveyed people and most said they'd prefer to see it in their local currency. I could do it server-side but then that meant I had to figure out a caching scheme and write more code than I wanted to. It would be kind of me to implement it server-side with some caching anyways, so that I don't hit the API too often but this page isn't trafficked heavily (less than a hundred hits a day).

@Joan Piedra: Indeed, forEach is available in newer browsers but could not be used directly with the NodeList returned by querySelectorAll. The NodeList looks like an Array but isn't and therefore, the forEach method would fail (hence the traditional for loop in the example).

@Jonathan, note that if (condition) { function fn() {} } is not allowed in ES5 strict mode, and will declare fn even if condition is falsy. Function expressions are allowed, though, so you could do something like:

var fn;
if (condition) {
fn = function() {};
}

In this case I think the ideal solution would be to use an IIFE:

condition && (function() {
function fn() {}
// do other stuff here that will only be executed if `condition` is truthy
}());

Love going simple with JS if I can. Definitely the way forward for simple sites.
That said if you use a cdn for popular libraries then generally it doesn't slow down for the end user, as its a fair bet that they already have the latest version cached.

Please, for the sake of the children; always specify a base for your integer parsing. If you are making judgement on currency exchange rates and parse that leading zero... well lets just say it could be a very very bad day.

It is important to know how to use JavaScript, but I would still use jQuery for this task. Because jQuery is so ubiquitous I assume the Google CDN hosted copy is cached on most machines so the is no serious delay to loading it. jQuery code to do this task would be simpler and easier to read and maintain and requires no code to account for browser compatibility issues.

@NotApplicable.com: Please, for the sake of the children, I wrote the HTML and the JavaScript, so I'm rest assured my prices will not have leading zeros. :) (but point taken)

@Adam: cache miss ratios and browser performance still put a burden on users and browsers. The browser still has to parse 91k of JavaScript just to do something that will take approximately the same amount of code. Why plan for the best case scenario?

Great article, nice to see somebody using open exchange rates! Would be awesome to get a clicky link to it in the post - it's a free service so relies on people spreading to word for it to be maintained.

JSONP is risky -- if you ever plan on offering private (or potentially confidential) data secured through session cookies and the like, JSONP opens your site to XSS attacks, in a way that real JSON and XML don't.

I really do try to avoid jQuery wherever I can (I wrote something to this effect in a reply to one of your posts on animations). The short version; if you know jQuery but can't understand the underlying code then you're just building on sand (and I simply don't buy the 'its cached from a CDN anyway' argument).

For an extra couple hundred bytes or so you could have probably extended support down to IE 6 by using getElementsByClassName and implementing a custom function for browsers that don't support it--you know, like this http://snook.ca/archives/javascript/your_favourite_1 ;-)

Like you said, it's not important in this case. But if someone else had a more critical reason to support more browsers, there are still lots of options outside of jQuery.

I would like to note that this was the third SCR that I tried, and of the three this one had the worst burn. I am really hipong with some more aging these will turn out to be a decent mild smoke. I like the flavors associated with the Habano wrapper but this one didn't utilize them well. A great Habano to try is the Padilla Habano. The wrapper is a lighter shade but the flavor profile is much better.

Sorry, comments are closed for this post. If you have any further questions or
comments, feel free to send them to me directly.