Even with a name only an engineer could come up with, querySelectorAll() is pretty awesome

January 8th, 2012

One of the reasons I put up tutorials and code on this site is because if something is wrong, someone will let me know, usually within an hour or two of me posting it. I’m actually really happy with how little it happens and most of the time it’s someone pointing out something I missed or a different way of doing it. Recently, I put up a post about the JavaScript method getElementsByClassName where I talked about how it how it might now work the way you would think it should. This lead the a comment saying I should have used querySelectorAll(). So why didn’t I?

Well, the main reason was I didn’t know it could do what I wanted. In every example I’ve seen of querySelectorAll looked like this:

1
var myArray = document.querySelectorAll(‘div’);

I didn’t realize I could pass in a class name and it would select everything with that class:

1
var blueDivs = document.querySelectorAll(‘.blue);

If you take a look at the Mozilla Developer Network page, the example it has is:

1
var matches = document.querySelectorAll("div.note, div.alert");

But up until recently, that was a huge red error message!

So what makes querySelectorAll so great? Well, I made an example that changes the class on a group of divs and then allows you to change it back even though it found the divs in the DOM using the class name. This wouldn’t be possible if I used getElementsByClassName because that live node list would become empty as soon as the class names were changed. Here’s the HTML and CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>querySelectorAll Test #1</title>
<style>
body {
 margin:0;
 padding:0;
}
.wrapper {
 width:550px;
 height:160px;
 margin:30px auto 0;
}
.wrapper > div {
 margin-right:10px;
 float:left;
}
.box {
 background:blue;
 width:100px;
 height:100px;
}
.border {
 background:red;
 width:90px;
 height:90px;
 border:5px solid black;
}
button {
 width:140px;
 height:30px;
 display:block;
 margin:auto;
}
</style>
</head>

<body>
<div class="wrapper">
 <div class="box"></div>
 <div class="box"></div>
 <div class="box"></div>
 <div class="box"></div>
 <div class="box"></div>
</div>
<button id="change">Change the class</button>
</body>
</html>

This just makes five divs that are 100 pixels in width and height with a blue background to start. There a button that when clicked will change the class on the divs. Here’s the JavaScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
(function() {
 var boxes = document.querySelectorAll('.box'),
       change = document.getElementById('change'),
       currentClass = 'box';

 if (document.addEventListener) {
   change.addEventListener('click', changeClass, false);
 } else if (document.attachEvent) {
   change.attachEvent('onclick', changeClass);
 }

 function changeClass() {
   if (currentClass === 'box') {
     classLoop('border');
     currentClass = 'border';
   } else if (currentClass === 'border') {
     classLoop('box');
     currentClass = 'box';
   }
 }

 function classLoop(newClass) {
 for (var i = 0; i < boxes.length; i++) {
   boxes[i].className = newClass;
  }
 }
})();

So, when the button is pushed, the class is changed on all five divs from box to border. Check out the demo. And because I used querySelectorAll fo find them in the DOM, then even though the class on all the divs has changed to border, they’re still in the boxes array. This allows the class to be changed back to box when the button is clicked again. I included attachEvent because this will work in Internet Explorer 8, which makes this all kinds of useful!

I have to say, I really wish they’d picked a different name, it’s pretty clunky and doesn’t really describe what it does which I think is important for beginners. I’ll be honest with you, I’ve probably seen this function before but because it’s name, it didn’t catch my eye. I’m sure this makes perfect sense to the people that added it to JavaScript, but really, if you asked someone what it did, they would probably have a hard time guessing.

I’d like to see knowledge of this method spread more to front-end developers that only really know jQuery, because I don’t know how many times I’ve seen jQuery used just to select DOM elements. Hopefully, some devs will start using this so they don’t have to load jQuery just to select some divs.

Recreate the 3D slider effect from the Android home page

December 28th, 2011

I think I’ve mentioned on here before that once in a while I’ll see an effect on a web page and I’ll become obsessed with how it was down. The latest thing to catch my attention is the 3D slide effect that’s on the home page of the Android site. It’s a great effect and makes use of CSS3 3D transforms. But it does continue a trend I’ve been seeing from Google lately, it only works in Webkit browsers like Chrome and Safari although it could be set to work in Firefox 10, which is in beta right now. This might be because Google wanted it to work a certain way and Firefox’s implementation doesn’t work quite the same as Webkit’s.

The trick to how the effect works is that it’s powered by CSS but it uses JavaScript to trigger the effect. And the CSS it uses are translateX, transitions and animations. The animations are used to create a fade effect when the slider moves more than one “slide”. I’m not going to go step by step on how to build this, I’ll just go over the key parts and then if you really want to build your own version, you can go through the demo I’ve created. Here’s our basic HTML:

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="box-wrapper">
 <div id="box-container">
   <div id="home" class="box">
   </div>
   <div id="about" class="box">
   </div>
   <div id="work" class="box">
   <div class="image-left">
   </div>
   <div id="contact" class="box">
   </div>
 </div>
</div>

First off, anytime you use 3D with CSS, then you need to set the perspective:

1
2
3
4
.box-wrapper {
 -webkit-perspective: 600px;
 -webkit-perspective-origin: 2000px -200px;
}

A div with the class box-wrapper is the wrapper div for everything. The perspective property is set to 600 pixels, which essentially means the content is 600 pixels away on the z index. Next, the perspective-origin property is set to 2000px on the x axis and -200px on the y axis. This sets up the view that the user has. Next, we need to set up our transform-style:

1
2
3
4
#box-container {
 -webkit-transform-style: preserve-3d;
 -webkit-transition: -webkit-transform .6s ease-in-out;
}

Inside box-wrapper is a div with the id of box-container. I’ve set the transform-style to perserve-3d. There’s only two options, perserve-3d or flat, the first says everything should be positioned in 3D space, the other positions everything on the same plane as the container element.

Now it needs some JavaScript to set up the translateZ property of all the divs. The reason I decided to use to set all the z axis positioning on the divs is mainly because it allows you to add or remove divs without worrying about setting anything for them manually.

1
2
3
4
5
6
var startDist = 0;
boxContainer.style[transform] = 'translateZ(' + startDist + 'px)';
for (var i = 0; i < boxes.length; i++) {
 boxes[i].style[transform] = 'translateZ(' + startDist + 'px)';
 startDist -= 400;
}

First thing this does is set the translateZ property of the box-container div to 0. Next, the boxes array contains all the divs with a class of box and in the loop they are all given a translateZ value that’s 400 less than the previous one.

The basics to how this works is this, there’s four divs, the first one is 0, the next -400, then -800 and finally -1200. To get the moving through 3D space effect, the box-container div’s translateX value is changed to be the same as the one we want to see, so if the 3rd one is selected, it will be set to -800 and that div is the one in the view port. To trigger this effect, the translateX of the box-container will be set depending on what link is clicked:

There’s one other effect that really helps flesh this out and that’s when the user clicks on a div that not the next div, say they click on div 3 when they’re currently on div 1, there’s a nice fading animation to make it look like the user is moving through the other divs. First the animation:

1
2
3
4
5
6
7
8
9
10
11
@-webkit-keyframes half-fade {
 0% {
   opacity: 0;
 }
 50% {
   opacity: .4;
 }
 100% {
   opacity: 0;
 }
}

So this just fades the div in to 40% opacity and then back to zero to add to the transition effect. To add this effect, there’s a class called transition:

1
2
3
.transition {
 -webkit-animation: half-fade .6s ease;
}

What happens is that if the user is going from say, div 1 to div 3, then div 2 would have the transition class added to it and you’d get that fade effect. But there’s one problem, once a CSS animation is fired, there’s no way to restart it. This was the part that caused me the most problems but a quick search lead me to CSS-Tricks, where of course Chris Coyier had the answer. The solution is that you have remove the element and then add a new version of it. Luckily, that only takes 5 lines of JS:

1
2
3
4
5
function clone(i) {
 var el = boxes[i];
 var nel = el.cloneNode(true);
 el.parentNode.replaceChild(nel, el);
}

This code gets the element, clones the element and then replaces the element with the new element. This allows use to reset the animations.

Poke around the code in my demo. I didn’t use jQuery because A) Google didn’t on their site and B) because I want to make sure that I don’t rely on jQuery for everything. I made my demo to work in Firefox and also future proofed it to work in the other major browsers for the one day when they include 3D transforms.

One other thing, in at least my version of Chrome, the dev channel on Windows 7, you can’t click on either of the back two divs, in my version or on android.com. The same goes for Firefox. It does let you click on them in Safari, so I’m guessing this is a temporary bug but one that really make using this on real sites impossible, hopefully it gets fixed soon.

getElementsByClassName might not work the way you think it does

December 4th, 2011

I think a large amount of web designers and developers are like me, they start out using jQuery and then move to coding more with pure JavaScript. I’m not saying one or the other is better, although I’ve come to prefer when I can do something in a couple of lines of JS rather than load in jQuery. But one of the things I’ve come to learn pretty quickly is that just because I think something in JS should work similar to something in jQuery, it usually doesn’t. Remember, jQuery’s main purpose is to make things quicker and work cross browser.

Something that caused me a little bit of grief was getElementsByClassName. Now, if you’re at all familiar with JavaScript, then you’ve had to have used getElementById. For the most part, this in pure JavaScript:

1
var canvas = document.getElementById(‘canvas’);

is the same as this:

1
var canvas = $(‘#canvas’);

In fact, one of my biggest pet peeves has become people that use jQuery just to select an element and don’t use it for anything else when getElementById will do the exact same thing for them.

Alright, so let’s say we have this HTML:

1
2
3
4
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>

And we want to select all those divs with the class name box. With jQuery, it’s the same as selecting the id in the previous example:

1
var boxes = $(‘.box);

If you console.log boxes then you’ll find an array containing the four divs with the class box. And we can manipulate those divs with code. Now let’s say you wanted to do this with pure JavaScript, you’d look and think that getElementsByClassName should do the same thing.

1
var boxes = document.getElementsByClassName(‘box’);

This will also give us an array containing those four divs but it’s not really the same thing, it’s a live nodeList of those elements. What does that mean? Well, take a look at these two examples, a jQuery one and a JavaScript one. If you click Add otherBox Class and then stretch boxes, you’ll see you get two different results. The reason for this is because when we find those divs using jQuery, it keeps them in the array boxes, so when we change the class of the fourth div to otherBox and then add the stretch class to the divs in the boxes array, the fourth div will still double in height.

But in the JS version, the fourth div doesn’t stretch because when the class is changed from box to otherBox, that div is removed from the boxes array. This is because, as I mentioned before, it’s not normal array, it’s a live nodeList. So, whenever a change is made, it updates itself to only include the elements that currently have that class name.

This can be one of the most frustrating things when you switch from using jQuery to pure JavaScript, things don’t always work the way you’re used to or think they should. This is one of those situations where using Firebug or Webkit’s Developer tools will help you figure out what’s going wrong. And don’t forget to use resources like Mozilla’s Developer Network, you’d be surprised what you can learn when you look at code examples.

Working with CSS3 can be fun but it can also be amazingly frustrating

November 27th, 2011

I recently decided to redesign my site and the main CSS3 effect I want to use works great in Webkit browsers but not so much in Firefox, at least not yet. I know you’re thinking, wait, what about Opera or IE? Well, over 80% of my visitors are Chrome or Firefox users, so I figure I’ll make sure it works in there first and I’m pretty sure it will work in IE10 whenever that’s released. And I’ll get around to Opera, I swear!

Imagine this, I’m working along, getting this idea I have to work in Chrome, but the site I saw that inspired my idea only works in Chrome. And then I see that CSS3 3D transforms now work in Firefox 10. So I start messing around and seeing I can get this to work in Firefox. I’m using CSS3 tranforms, but I’m using JavaScript to set the CSS and the first thing I discover is that while the Webkit version makes sense:

1
el.style.webkitTransform = ‘translateZ(-400px);

The Firefox version does not. You’d think it would be this:

1
el.style.mozTransform = ‘translateZ(-400px);

But it’s not. That won’t work, you have to capitalize the m:

1
el.style.MozTransform = ‘translateZ(-400px);

I only found this out be Zachary Johnson did some digging and as far as I can tell, this is the only mention out there about how to properly write it. Problem solved now, right? I mean all the demos using CSS3 for Firefox that have translateZ working fine. But my test still wasn’t working and in fact I wasn’t even sure you could use CSS transition on the translateZ property in Firefox. It turns out you can but not if the CSS property is set as an inline style with JavaScript, which is needed for my idea to work properly. So the transition works right if it’s CSS but not if it’s JavaScript powered in Firefox. And in Chrome, it works both ways.

I’m still going to redesign my site because even though the 3D effect will only work in Chrome, at least right now, I’ll still get a fade in and out effect in the other browsers. The main traffic going to my site is web designers and developers and since over 40% of them use Chrome, a decent amount of visitors will site the site the way I intend them to. I’m sure Firefox will add the missing functionality sooner than later, so I’m not too worried about them missing out.

Cutting edge effects are pretty sweet, but you better have the patience to deal with the differences between browsers. Nothing can be more frustrating than when something isn’t working because the browsers use different syntax.

Stuff they don’t tell JavaScript noobs: Making your arguments optional

November 16th, 2011

One thing that took me a while to grasp fully when it came to programming was passing arguments to functions. I don’t know why but it was one of those things that I just got one day. But something that took me a while to learn is how to set up arguments to be optional. And once again, as with most of the things in my noobs series, it’s pretty simple when you know what you’re doing.

So first off, what do I mean by passing an argument to a function? It’s when you pass one or more objects to a function, something like this:

1
2
3
4
5
6
function add(a, b) {
  return a + b;
}

var answer = add(1, 2);
console.log(answer); // logs 3

I’ve created a function called add that accepts two arguments, a and b. It then adds the two arguments and returns it. So I’ve passed two arguments to the function. Pretty simple stuff but if I only passed one number to it, it would break. We can set up our function to still work, even if only one number is passed.

1
2
3
4
5
6
7
8
function add(a, b) {
  this.a = a;
  this.b = b || 100;
  return this.a + this.b;
}

var answer = add(4);
console.log(answer);

Looks pretty simple to the first one but instead of just adding the two arguments, I’m assigning their values to this.a and this.b in the function. I’m doing this so that I can set up the b argument to be optional, essentially what I’m saying is that this.b = b or if there’s no b, then it equals 100. Now I can pass two numbers or just one and it will add that to 100.

While this shows what I’m talking about, it’s not really a practical example. Here’s one that’s a bit more realistic:

1
2
3
4
5
6
7
8
9
10
function myGreeting(name, greeting) {
  this.name = name;
  this.greeting = greeting || 'Hello, my name is ';
  return this.greeting + this.name;
}

var sayHello = myGreeting('Mike');
var sayHey = myGreeting('Bill', 'They call me ')
console.log(sayHello); // logs ‘Hello, my name is Mike’
console.log(sayHey); // logs ‘They call me Bill’

In this example, I’ve created a function called myGreeting that accepts the arguments name and greeting. It’s exactly the same as the previous example expect that it returns a string instead of a number.

Once you understand this, I think it will make your programs leaner and more efficient because you can create one function that performs the work of two.

Draw a rectangle using the mouse on the canvas in less than 40 lines of JavaScript

November 14th, 2011

One thing that is a lot easier than people think is using the mouse to interact with the canvas tag. To show how easy, I wrote some code that allows a user to draw a rectangle on the canvas. This will be the start of a more complicated drawing program.

All we need for the HTML is this:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Draw a rectangle!</title>
</head>

<body>
<canvas id="canvas" width="500" height="500"></canvas>
</body>
</html>

Now let’s get on to the fun stuff. The first thing we’ll do is declare our variables:

1
2
3
4
var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    rect = {},
    drag = false;

If you’ve worked with the canvas tag at all before then the first two variables should look familiar, we are finding the canvas tag in the DOM using it’s id and then setting the drawing context of the canvas to 2D. Next is sq which is an object that we’ll use to store the info for the rectangle we draw. And finally, drag, which is a Boolean that we use to check if the user is drawing the rectangleor not.

Now let’s add our listeners which we’ll use to run our functions:

1
2
3
4
5
function init() {
  canvas.addEventListener('mousedown', mouseDown, false);
  canvas.addEventListener('mouseup', mouseUp, false);
  canvas.addEventListener('mousemove', mouseMove, false);
}

We have three event listeners, one for when the mouse button is pressed, one for when it’s released and finally one for when the mouse moves. All three have been added to the canvas, not the window or document, so that a user can click and move the mouse around the page with out triggering our drawing functions. The mouseDown function is called first, so let’s write that one:

1
2
3
4
5
function mouseDown(e) {
  rect.startX = e.pageX - this.offsetLeft;
  rect.startY = e.pageY - this.offsetTop;
  drag = true;
}

When the mouse button is pressed down, the function mouseDown will find the position of our mouse using e.pageX and e.pageY and then subtract the offset from the left and top if our canvas isn’t in the left top corner. Finally, we set the drag Boolean to true. Next is the mouseUp function:

1
2
3
function mouseUp() {
  drag = false;
}

About as simple a function as we can get. When the user releases the mouse button, drag is set back to false because they can’t be dragging to create a rectangle if the button isn’t pressed. And now the function that will power everything, mouseMove:

1
2
3
4
5
6
7
8
function mouseMove(e) {
  if (drag) {
    rect.w = (e.pageX - this.offsetLeft) - rect.startX;
    rect.h = (e.pageY - this.offsetTop) - rect.startY ;
    ctx.clearRect(0,0,canvas.width,canvas.height);
    draw();
  }
}

In mouseMove, we first check to see if drag is true, if it’s false, the just means the user is moving their mouse around the canvas, if it’s true, then it means they want to draw a rectangle. If drag is true, then we need to follow the position of the mouse and calculating the width and height of the rectangle. To do this we need to subtract startX and startY from the current position of the mouse. Next we clear the canvas because if the drag is true and mouse is moving, that means the user is still drawing the canvas. Finally, we call a function called draw to actually draw our rectangle:

1
2
3
function draw() {
  ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
}

With the draw function, we draw the rectangle using the four points that we figured out using the mouseDown and mouseMove functions. The starting x and y coordinates are rect.startX and rect.startY and the width and height are set with rect.w and rect.h. This will be updating every time the mouse moves, so if the user shrinks or grows the rectangle, it will draw immediately. And of course, don’t forget to call:

1
init();

At the bottom, so that the event listeners to the canvas. Check out the demo here. View source for the complete code.

That’s it. Pretty easy to get everything up and running.

Stuff they don’t tell JavaScript noobs: Convert a string into a variable name

November 10th, 2011

Hey, I said this might turn into a series and it’s turned into a series of two! Last week, I put up a post about creating something you’d usually use jQuery to write using pure JavaScript. And as usual, I learned something I never expected to when I was writing my code. It turned out, I had no idea how to convert a string into a variable name. Of course, the answer turned out to simple, but it didn’t turn out to be the way I thought you would do it.

In my earlier post, I needed to see which link was clicked and then hide and display the colored divs based on that. Basically, if you clicked the blue link, then the page would only display the blue divs. I created a couple of arrays, blueDivs and redDivs and to make this work, I had to link the link with the id blue to the array blueDivs.

This is what I tried at first:

1
2
3
4
5
6
function showDivs(el) {
  var div = el + ‘Divs’;
  for (var i = 0; i < div.length; i++) {
    div[i].style.display = 'block';
  }
}

If I pass blue to the showDivs function, then blue plus Divs should give me blueDivs, right? Technically it does, but it’s a string and it’s not going to work because when the loop runs, it’s going to try to go through each character in the string. So this isn’t going to work for me. Why does this happen? Because JavaScript tries to guess what you want to do and any time you add anything to a string, the default result is to create a string. So if you were to write this:

1
2
var myNum = 1 + ' is a number!';
console.log(typeof(myNum));

Even though we’ve got a number in there, it will log out string as the type. So how do I change a string into a variable name? Well, a variable is really an object, so I need to convert our string into an object. How do I do this? Like this:

1
2
3
4
5
6
function showDivs(el) {
  var div = this[el + ‘Divs’];
  for (var i = 0; i < div.length; i++) {
    div[i].style.display = 'block';
  }
}

If you console.log(typeof(div)) on on this example, it will give you an answer of object. In fact, window[el + ‘Divs’] would do the same thing, in this case, I’m using this because it’s not a global variable. Now the variable div will equal blueDivs if I’ve passed blue to showDivs. And when the loop runs, then it will cycle through the blueDivs array.

Once again, this is one of those things that you probably won’t learn until you run into a situation that you need it.

I’ve been thinking about jQuery

November 8th, 2011

The more and more that I work with JavaScript, the less and less I find myself using jQuery. And then I saw this tweet and it made realized that there are two types of jQuery users. There’s the designers and HTML/CSS people that have no interest in programming but use jQuery to add functionality and effects to sites. And there’s the developers who use jQuery as a starting point and move more and more into using pure JavaScript. jQuery isn’t meant more for one group than the other and the great thing about it is that it works for both.

For me, the best thing about jQuery is it made me realized JavaScript isn’t the worst invention in the history of the web like I’d been told. And that the browser is capable of things that perviously I’d only been able to achieve with Flash. In fact, at work for a time, my catchphase must have been “We don’t need Flash to do that.”

But, I’m beginning to sense an wave of anti-jQuery sentiment amongst the web development community. jQuery is on half of the top 100,000 web sites or something like that. And I’ve noticed this being pointed out more and more on tech sites when they talk about jQuery. It almost reminds me of how Adobe and other Flash supporters liked to mention that the Flash Player was on 97% of computers. So what if jQuery is super popular? If you don’t like it, aren’t you just being a web hipster? Maybe, but what if the feelings aren’t towards jQuery itself, but the fact that it seems every designer and developer feels the need to have some jQuery effect on their site, whether it needs it or not.

I’m a fan of Flash and I think it’s the best development tool for games right now, especially if AIR works as good as Adobe claims it does on mobile devices. But I always shake my head when I visit a web site and it has a Flash built navigation. I can’t think of a single reason that Flash ever needs to be used for something like that. People aren’t impressed with the cool lightning effects anymore, in fact, they’re probably annoyed by it. But now it seems jQuery has stepped up to replace those cool nav effects with their own. Done right, a little arrow on the bottom of a web site’s navigation sliding back and forth can add to the site. It’s too bad I’m beginning to see more and more complex animations on drop downs that add nothing to the site.

Wait, am I saying using jQuery on every site is bad? Isn’t that a little hypocritical of me? I’m not saying that at all. In fact, I use jQuery on almost every site I build. But I’m not using it to add effects to most of them, I’m using it to add functionality that some browsers are missing, browsers like IE7 and IE8.

Here’s the thing, I think we need to remember that while jQuery is awesome, it’s not the solution to everything. We need to be careful that we don’t create whatever the jQuery version of Flash intros might be. And there’s no such thing as a jQuery developer and knowing jQuery doesn’t mean you know JavaScript.

Become a better JavaScript developer by recreating jQuery effects in raw JS

November 2nd, 2011

A couple of days ago, a client wanted a couple of pages of videos changed to one page with a series of thumbnail links to the videos. And they wanted a way to show all the video thumbs or ones in certain categories. And, of course, I didn’t have a lot of time to build this, so I turned to jQuery. I ended up building a page like this. There’s no fancy effects but it gets the job done. Later on, I began to wonder if I could do the same thing in JavaScript and if it would be anywhere near as simple to write.

First, let’s take a look at the jQuery I wrote to get the effect the first time:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$(function() {
  var divs = $('#wrapper div');

  $('#blue').click(function(e) {
    e.preventDefault();
    showBox('.blue');
  });
  $('#red').click(function(e) {
    e.preventDefault();
    showBox('.red');
  });
  $('#show-all').click(function(e) {
    e.preventDefault();
    $(divs).filter('.box').show();
  });
 
  function showBox(box) {
    $(divs).hide();
    $(divs).filter(box).show();
  }
 
});

I’m getting all the divs inside the wrapper div and putting them into a variable called divs. Next, I check to see which of the links you click on and if it’s blue or red, then I run a function called showBox, which hides all the boxes and then shows the ones I want to be shown. If the show-all link is clicked, then I just show all the boxes. I hide all the boxes because it’s easier then remembering which ones are showing and which ones aren’t.

It’s pretty simple and it’s like jQuery code you see everywhere on the web. I used jQuery exactly for the reason it was created, to add an effect to a site quickly and easily and there’s nothing wrong with doing it this way. But I want to get as good as I can at JavaScript, so why not see if I can do this without jQuery. And I did it and I actually learned a thing or two.

Let’s take a look at JavaScript code that does the same thing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var divs = document.getElementsByClassName('box'),
    blueDivs = document.getElementsByClassName('blue'),
    redDivs = document.getElementsByClassName('red'),
    blue = document.getElementById('blue'),
    red = document.getElementById('red'),
    showAll = document.getElementById('show-all');

function hideDivs() {
  for (var i = 0; i < divs.length; i++) {
    divs[i].style.display = 'none';
  }
}

function showDivs(el) {
  var div;
  if (el === divs) {
    div = el;
  } else {
    div = this[el + 'Divs'];
  }
  for (var i = 0; i < div.length; i++) {
    div[i].style.display = 'block';
  }
}

function click(e) {
  e.preventDefault();
  hideDivs();
  var target = e.target.id;
  if (target === 'show-all') {
    showDivs(divs);
  } else {
    showDivs(target);
  }
}

blue.addEventListener('click', click, false);
red.addEventListener('click', click, false);
showAll.addEventListener('click', click, false);

This does the exact same thing as the jQuery code. I used getElementsByClassName to create an array of divs and I also had to create arrays for the blue and red divs, which jQuery did for me. And the event listeners do the same thing as the click method of jQuery. Really, the only difference is that I had to write loops through the arrays myself, which is something else that jQuery did for me in the earlier code.

So people are probably thinking, why do this:

1
2
3
for (var i = 0; i < div.length; i++) {
  div[i].style.display = 'block';
}

when jQuery will just let you do this:

1
$(divs).filter(box).show();

Well, that’s what jQuery is doing behind the scenes. And the big difference going here is this, yes, the JS is about twice as much code in the HTML page, but to make the jQuery work, I need to load a 31KB file. With the raw JS, I have 40 lines or so.

I’m in no way ripping on jQuery here, I use it all the time and on the site I used this on was using jQuery for other things, so it was already loaded. I like to do things like this because it’s a challenge with a definite goal. Challenging yourself like this will help you become a better JS developer and it might lead to you relying on jQuery less.

Some things I’ve learned in 3 years as a web developer

October 31st, 2011

There have to be few industries that move at the speed that the web does. I can’t believe how many things I learn in school are useless now. Yes, that’s right, I learned Adobe Director. In fact, I remember seeing the A List Apart previewing HTML5 and thinking, “Man, that’s going to be so cool in the future.” Flash was going to take over the web and JavaScript was the worst thing ever invented.

So three years later, in a world of hover cars and jet packs, what do I know now? Well, other than the fact that I’m crazy mad that we don’t have hover cars and jet packs, I know that I’m working on with technologies and programming languages that I never thought I would. I remember three years ago looking at people that spent a majority of their time working with HTML, CSS and JavaScript and thinking “Really? That’s what you do? That’s got to be pretty boring.” Now, I’m one of those people and I totally enjoy what I do.

I’ve learned that every programming language on the web sucks and is going to die. Or it’s totally awesome and is going to take over. Or make a comeback. Or it’s underrated. For every blog post I’ve see about Java being this close to disappearing from the world forever, followed by one talking about how there’s never been more Java work out there.

I’ve learned that people can get way too involved in whether the language they like is better than one they don’t. Whether or not a language uses curly braces shouldn’t matter if the end product is great or if the programmer likes it. Pick your language and become awesome at it. Being awesome at PHP will always be better than being OK at Ruby. Unless, of course, you really hate curly braces.

I’ve learned that we as web designers and developers should never let a company tell us what technologies should do. But at the same time, don’t refuse to use any technology just because of who makes it.

I’ve learned that comparing yourself to your idols can be the worst thing you can do. Just because they can make something amazing using a cutting edge feature, doesn’t mean they know how to build a WordPress theme or a Flash game. Don’t look down on what you can do because of what others can do.

I’ve learned that just because a blog gets thousands of hits a day, doesn’t mean you should give a crap what that person has to say. And I’ve learned that just because a person has 30 followers on Twitter, doesn’t mean they don’t know what they’re talking about.

Some things have stayed the same. Superman is still the best superhero. Apple fanboys are annoying. And I’ll try every code editor I come across.