However small your site may be, you might often need to manipulate your DOM to make it interactive. Of course, you would choose not use any library for as simple interaction as toggling an off-canvas navigation menu. Instead, you would prefer to use pure javascript to achieve such little tasks and keep the downloadable assets minimum. But often your code grows so large that you have to pay for increased page size more than the benefits you get. Although, the code for as simple DOM manipulation as this isn’t so long to hurt your page performance but if you have got to make tens of such little ‘DOM manipulations’, your code will grow larger and larger and then comes the responsibility to make your code as short and maintainable as possible to keep your site’s performance rocking.

 

Let’s take some examples to understand how we can make our DOM manipulations shorter that the usual.

 

The Off-canvas Menu

The Off-canvas menu has created a lot of buzz in the modern websites that sports responsive functionality. The off-canvas element that casts, usually a menu, pops in from the side and creates the clean overlaying effect. Most of us would go this way for making an off-canvas menu.

  1. Get off-canvas menu.
  2. Get the button clicking which toggles the menu.
  3. Add an event listener to the button and do the stuff inside the event handler.

 

The code for the same looks something like this:

[codepen_embed height=”268″ theme_id=”21620″ slug_hash=”EPNeLr” default_tab=”js” user=”devstreak”]See the Pen <a href=’http://codepen.io/devstreak/pen/EPNeLr/’>Unoptimized Off-canvas Menu</a> by Devstreak (<a href=’http://codepen.io/devstreak’>@devstreak</a>) on <a href=’http://codepen.io’>CodePen</a>.[/codepen_embed]

 

This works flawlessly, but take a notice on the number of lines of code. The code accounts into four (main) lines. Now suppose we have got to put some other manipulations like this one. To reduce the page size, couldn’t we make it lighter? Indeed, we can.

 

[codepen_embed height=”268″ theme_id=”21620″ slug_hash=”adBaKx” default_tab=”js” user=”devstreak”]See the Pen <a href=’http://codepen.io/devstreak/pen/adBaKx/’>Optimized Off-canvas Menu</a> by Devstreak (<a href=’http://codepen.io/devstreak’>@devstreak</a>) on <a href=’http://codepen.io’>CodePen</a>.[/codepen_embed]

         

Here we get only the button which toggles the class ‘off-menu-opened’ on the menu and instead of explicitly selecting our menu using querySelector method, we access it using using the parentElement property on the button when it’s clicked. Take a notice of reduced lines of code. The newer code is one line shorter. You might say this won’t make much difference in performance but let me remind you again when you have got many such DOM manipulations, it does make a difference. You can save ten lines for ten such manipulations.

 

Login/Sign Up Modals

In this example, we are going to create a very common login and sign up modal. We have a button, clicking on it will trigger the login modal. The login modal has a ‘Sign Up‘ button, that on clicking triggers the signup modal further. Following is the basic markup we are going to use. Optional markup has been skipped. You can view full markup in the demo below.

 

<button class="button login">Login</button>
<div id="modalLogin" class="modal">
<button class="button close">close</button>
<form action="none">
<section class="btn-con">
<button class="button submit">login</button>
<button class="button signup">sign up</button>
</section>
</form>
</div>

<div id="modalSignup" class="modal">
<button class="button close">close</button>
<form action="none">
<section class="btn-con">
<button class="button submit">sign up</button>
</section>
</form>
</div>

 

The following code snippet is the basic Styling used for both of our modals.

.modal {
position: absolute;
top: 40%; left: 50%;
margin: auto;
width: 60vw;
min-height: 70vh;
background: #0eade0;
transform: translate(-50%, -50%) scale(0);
transition: .1s ease-out;
overflow: auto;
}

 

We add a class ‘opened’ to open the modal

.opened {
transform: translate(-50%, -50%) scale(1);
}

 

Now, let’s start with the Javascript. In a nutshell, what we can do is

 

  • Select both the modals and all the four buttons to be used for opening and closing the modal.
  • Add four event listeners, two for opening modals and two for closing them.

 

According to the markup, the code below works fine

 

[codepen_embed height=”520″ theme_id=”21620″ slug_hash=”zroJJe” default_tab=”js” user=”devstreak”]See the Pen <a href=’http://codepen.io/devstreak/pen/zroJJe/’>Login/Singup Modals – long version</a> by Devstreak (<a href=’http://codepen.io/devstreak’>@devstreak</a>) on <a href=’http://codepen.io’>CodePen</a>.[/codepen_embed]

   

We can get quite happy that this does our work. But our code is still not smart enough. What if you put some more call-to-action buttons in future? It is going to be a lot of work. Imagine adding selectors for each button, the modals to open/close and separate event handlers for all these buttons. Don’t you think our code will become like a spreadsheet where if there comes any new record, you have to make a bunch of changes manually? We need such a code which makes it easier for us to add more button controls in future without making our code huge and unmaintainable. The first thing that is making our code this huge is the selectors at the very top. Can we keep ourselves from selecting each button explicitly? We can indeed, by making use of querySelectorAll with a helper function.

//helper function
function $$(selector) {
    var elements = document.querySelectorAll(selector);
    return Array.prototype.slice.call(elements);
}

 

You might have come across the function above if you ever used Lea Verou’s projects. She uses it very frequently in her code.

Unlike querySelector, that selects the first element it encounters in the DOM, querySelectorAll selects all the matching elements passed in the argument and returns a list of them. We use ‘slice.call‘ on Array.prototype object which returns an array of all the elements selected by querySelectorAll.

Now we can iterate over all the items stored in the array returned by $$ function. We can do so using either a for loop, forEach or map (maybe there are more ways I may not be aware of). forEach and map seem to be more semantic as we are  dealing with an array. Let’s go for forEach.

$$(".button").forEach(function(el) {
  el.addEventListener("click", function() {
   //do stuff
  });
});

 

The forEach accepts a handler (a function) which accepts three main arguments element (it could be anything you like), index and array. The element is the element that is currently being processed, the index is the index of the element being processed starting from 0 according to its order in the document. To know more about it, you can read further at MDN.

 

Now that we have selected all the buttons having class .button, let’s get into doing our main stuff. There are a lot of buttons having class .button. So how do we decide which button does what? Look at the markup at the beginning, you can see that along with the class button, we have also assigned a unique class to each button. Let’s grab that class when any button is clicked.

$$(".button").forEach(function(el) {
el.addEventListener("click", function(e) {
  var _class= this.classList[1];
    //rest of the code
   });
});

 

Here, we define a variable _class which stores the second class of the clicked (this) button. Note that classList’s index also start with 0;

 

Now we will use the switch statement on “_class” to perform different actions for different buttons.

 

$$(".button").forEach(function(el) {
el.addEventListener("click", function(e) {
  var _class= this.classList[1];
  switch(_class) {
     case "login": modalLogin.classList.add("opened");
                   break;
     
     case "close": this.parentElement.classList.remove("opened");
                   break;

     case "signup": modalSignup.classList.add("opened");
  }
  e.preventDefault();
  });
});

 

Here’s the demo for the above code.

[codepen_embed height=”520″ theme_id=”21620″ slug_hash=”PZbdxp” default_tab=”result” user=”devstreak”]See the Pen <a href=’http://codepen.io/devstreak/pen/PZbdxp/’>Login/Sinup modals – short version</a> by Devstreak (<a href=’http://codepen.io/devstreak’>@devstreak</a>) on <a href=’http://codepen.io’>CodePen</a>.[/codepen_embed]

 

Here switch accepts _class which is the class of the clicked button. We define the list of cases with the class (second ones) names of the buttons as their name. Suppose the button with class .login is clicked, _class stores the string “login” and the code under the case “login” is run which adds class ‘.opened’ to the login modal and opens it. Notice that for close button we use parentElement from our previous  example which closes the modal it is present in. But make sure all the close buttons are direct children of the modal according to the code we have above. however, if it’s somewhere deep, you can always chain parentElement like this-

this.parentElement.parentElement.classList.remove("opened");

 

We use e.preventDefault() to prevent the default behaviour of the browser. In this case, to prevent the form action exclusively. All that is fine but you would be wondering where the heck ‘modalLogin’ and ‘modalSignup’ which seem to be like variables came from when we have not declared any such variables to select our modals. Did you notice that these are same as the IDs our modals have-

<div id="modalLogin" class="modal">
<!-- rest of code -->
</div>

<div id="modalSignup" class="modal">
<!-- rest of code -->
</div>

 

Yes, those words are referencing to their IDs only. Actually, when you assign an ID to an element, it automatically becomes a global variable of Window object i.e. we don’t need to select them, we can access them just by their ID names anywhere in your javascript. For more illustration, let’s have a short example.

<p id="para">I'm a paragraph proudly owned by an ID</p>

 

Now you can style the element. Let’s render this paragraph in a colored text.

 

para.style.color= "tomato";

//do anything with para like you would do with the element
//you would have select using querySelector, getElementById etc.

 

Using single event handler for multiple events

Suppose, we have got some text fields and our only work with them is to get user-entered values from them and use those values in something. In such a case, it would not be wise enough of us to create multiple event handlers for each text field, a problem we have discussed earlier in this post. It does our work but doesn’t let us remain DRY which is extremely important for our code to be progressive. So, let’s get to our last example.

 

We have the following markup

<div class="input-con">
 <label for="inputFirst">Input 1</label>
 <input type="text" class="in" id="inputFirst"/>
  <label for="inputSecond">Input 2</label>
 <input type="text" class="in" id="inputSecond"/>
</div>

 

This time, without discussing the long version code as in other previous examples, let’s get straight into the short one

inputFirst.addEventListener("input", handleInputs, false);
inputSecond.addEventListener("input", handleInputs, false);

 

We use separate event listeners which point to the same event handler i.e. ‘handleInputs’. Now let’s see what our handler function looks like

function handleInputs(e) {
 var target= e.target,
     value= this.value;

 switch(target) {
   case inputFirst: let inputFirst_value= value;
                    console.log(inputFirst_value);
                    //do other things
                    break;

   case inputSecond: let inputSecond_value= value;
                     console.log(inputSecond_value);
                     //do other things
                     break;
  }
}

 

[codepen_embed height=”400″ theme_id=”21620″ slug_hash=”jWVvdz” default_tab=”result” user=”devstreak”]See the Pen <a href=’http://codepen.io/devstreak/pen/jWVvdz/’>jWVvdz</a> by Devstreak (<a href=’http://codepen.io/devstreak’>@devstreak</a>) on <a href=’http://codepen.io’>CodePen</a>.[/codepen_embed]

 

Open your console and try changing values of both the text fields.

 

We again make use of switch here. We store the target property of our event(e) object passed to our handler and then pass it to switch. ‘target’ property (e.target in this case) points to the element the event is being called on, in our case the two text input fields (inputFirst & inputSecond). Further, we store the value of input field ‘input’ event is currently being called on in a variable ‘value’s, create separate cases for each input field and do the things we want with the value(s).

 

Browser Support

Everything we used in this post is widely supported. We don’t need to hesitate using the properties like parentElement, which are very well supported in almost all the browsers.

 

Conclusion

Sometimes our code becomes larger for the basic interactions we build for our sites/web apps. Often we use libraries and frameworks to achieve small UI tasks, that fades away the ability of our sites to be small but still performant. We can just use vanilla javascript if out site/web app is of small-scale. Let’s not trouble our sites with libraries and frameworks until we really and seriously need them.

Share on Facebook Tweet on Twitter Post on Google+ Buffer