Doop: DOM object oriented programming

By
Grant Vinson

DOOP

I would like to show an example of what I call "DOOP" or DOM Object Oriented Programming.


var MobileMenu = {
 showing: false, // a flag to tell if the mobile nav is showing or not.

/**
* Initializes the object with functions to run
* at the DOM ready event.
*/
 init : function() {
	MobileMenu.mainNav: $('.main-nav').clone(), // the main nav element
	MobileMenu.mobileNav: $('#mobile-nav'), // the mobile nav element
	MobileMenu.mobileNavWrapper: $('#mobile-nav-wrapper'), // will hold all nav elements
	MobileMenu.hamburger = $('#mobile-nav .hamburger');
	MobileMenu.injectNav();
 },

/**
* Injects the nav into the mobile nav wrapper element
* and then sets the event listeners
*/
injectNav : function() {
	MobileMenu.mobileNavWrapper.prepend(MobileMenu.mainNav)
	MobileMenu.setEventListeners();
 },

/**
* Initialize all event listeners for the mobile menu
* (Currently just being used for the click/touchstart event
* of a hamburger icon)
*/
setEventListeners : function() {
	MobileMenu.hamburger.on('click touchstart', this.showMenu);
},

/**
* Run when the hamburger is clicked.
* If the mobile nav is not showing, add the
* css classes to animate it in. Else, remove
* the classes to animate it out.
* @param e = the event from the hamburger click
*/
 showMenu : function(e) {
	 e.preventDefault();
	 if (MobileMenu.showing === false) {
		 MobileMenu.hamburger.addClass('open');
		 MobileMenu.mobileNav.addClass('open');
		 MobileMenu.showing = true;
	 }
	 else {
	 	MobileMenu.closeMenu();
	 }
 },

/**
* [closeMenu description]
* @param e = the event from the hamburger click
*/
 closeMenu : function(e) {
	 MobileMenu.hamburger.removeClass('open');
	 MobileMenu.mobileNav.removeClass('open');
	 setTimeout(function() {
		 // Allows timing for css animation to complete
		 MobileMenu.showing = false;
	 }, 255);
 },
};

/**
* Initialize the MobileMenu object when
* the DOM is ready
*/
$(document).on('ready',MobileMenu.init());

This JavaScript file takes the main navigation and injects it into a mobile nav element when the DOM is fully loaded. It also sets event listeners to the hamburger icon to show/hide the mobile menu. I am not going to explain how each function works, but feel free to post questions in the comments below.

The CSS classes that are added in the above example translate the menu into view and changes the hamburger from three bars to an X. Each animation/transition is set to take 0.25 seconds. To render the animation more smoothly, I like to use CSS transitions instead of the top/right properties.

As you can see, this example is pretty easy to read, even if you aren't sure what is going on. The mobile menu is shown or hidden when something (the oh-so-loved/hated hamburger icon in this example) is clicked. I use "touchstart" as a listener for better mobile interaction.

Not real oop

If you are an experienced programmer with an extensive knowledge of OOP, you will notice that none of these functions have a return statement. When manipulating the DOM in such a way, I don't find them necessary. I do however use return statements when, let’s say, validating a form before submission. This is why I like to refer to this style of DOOP: we use JavaScript Objects to manipulate DOM elements based on certain events.

Functions within the Object may be called elsewhere in the code. The Object's functions are not private so, you may call MobileMenu.showMenu() elsewhere in your app if needed.

There aren't any cool tricks or awesome snippets of code in this but it is much easier to read rather than dumping all of the code inside of the $('document').ready() function. I use this style when I validate forms, show/hide a lightbox, add functionality for a mobile menu, capture the scroll position for parallaxing/animating elements into the view… it is just easier for us humans to read. With the Object's name as a declaration of a function, I know exactly what is happening when a function is called. MobileMenu.showMenu() tells me to show the mobile menu. DesktopMenu.showSubnav() lets me know that I am wanting to show a subnav on the desktop/large navigation element.

I hope this technique helps some of you clean up your code so others will be able to jump in and know where you are headed with these functions. If anyone has any ways to improve this style, I would love to hear from you. Again, I am not a genius.