Blogger Ever

Create a Javascript plugin using Javascript object oriented behavior

Create a simple Javascript plugin using native Javascript functions.

If you are willing to create a Javascript plugin then there are a lot of stuff to know if you are a beginner. jQuery plugin is quiet easy to create since there is complete API to do that. When I googled about creating a Javascript plugin I found a very few helpful articles or tutorials on that. Not surprising since many are there using jQuery and developers find ease to create a jQuery plugin. Short codes, complete docs, variety of usable functions and more.

Basically it is difficult to setup the starting, but if you know the basic Javascript stuff like creating a functions and basic to do functions then rest of the stuff is quite easy. Let me give a glance over it, Javascript's object oriented behavior, loops like for...of and for...in and prototype-inheritance are some major topics to read about first. If you have a good on it then have a dive on it.
See the Pen Javascript multi tab plugin by Mohammad Hamza Dhamiya (@hamzadhamiya) on CodePen.
I'm going to create a accordion multi tab plugin, so lets start with basic markup.

<div class='tab-outer'>
    <div class='tab-button'>
<a href='#content1'>Button 1</a>
<a href='#content2'>Button 2</a>
<a href='#content3'>Button 3</a>
    </div>
    <div class='tab-container'>
        <div id='content1'>This is content 1</div>
        <div id='content2'>This is content 2</div>
        <div id='content3'>This is content 3</div>
    </div>
</div>
Now we have a basic markup, lets move on to Javascript. Lets create an object.

// This is a self invoking function
(function(){

})();
We just invoked a function. Lets create a constructor, basically a constructor is like a machine that creates instances. We'll talk a more on it later in post.

// This is a constructor
this.Tabs=function(){
}
Now lets move on to create default options. These options will work as a fallback of non-required options. Because many stuff people don't like to edit so let give the folks some defaults. 

// This is a self invoking function
(function () {
    // This is a constructor
    var Tabs = function () {
        //defaults
        var defaults = {
            activeButtonClass: 'active',
            activeContainerClass: 'active',
            tabOuter: null,
            buttonContainer: null,
            contentContainer: null
        }
    }
})();
However there are only 2 defaults but required options are there: tab outer, tab button container and tab content container which are set to null means required to add. Next step is to replace defaults with passed argument. Argument is a value or object passed with every function. So now we are going to do that with for..in loop.

 var newer = arguments[0];
    this.options = replaceDefaults(defaults, newer);

function replaceDefaults(older, newer) {
      var anyOption;
      // Accessing each newer option
      for (anyOption in newer) {
        // Check whether this option present in argument[0] object
        if (newer.hasOwnProperty(anyOption)) {
          older[anyOption] = newer[anyOption]
        }
      }
      return older;
    }
Okay first we created a variable newer that holds an argument object. The arguments[0] describes the first object in argument array. Not to confuse but no matter how many options are passed they will come under single object, so just accessing the first object containing all the options.

Then we just introduced the object options. These options will be obtained through a function that actually put newer options into older options (kind of update). For...in loop is best for it since this loop goes through key and its value. New options updated, now lets move on to making the tabs work. So lets create a function and pass all options into that.

this.Tabs = function() {
    //defaults
    var defaults = {
        activeButtonClass: 'active',
        activeContainerClass: 'active',
        tabOuter: null,
        buttonContainer: null,
        contentContainer: null
      }
      // Since there are required options so we are going without if condition.
    // Since all arguments are under one object, so technically there is only a single argument passed.
    var newer = arguments[0];
    this.options = replaceDefaults(defaults, newer);
    startTab(this.options);
  }
function startTab(e) {
    // All options are accessed here through "e"
    var a = document.querySelector(e.tabOuter),
      b = document.querySelector(e.buttonContainer),
      c = document.querySelector(e.contentContainer),
      d = e.activeButtonClass,
      f = e.activeContainerClass;
    changeTab(a, b, c, d, f, b.children[0]);
    for (var i = 0; i < a.children.length; i++) {
      // if current child is actually the button container then...
      if (a.children[i] == b) {
        for (var o = 0; o < b.children.length; o++) {
          
          b.children[o].addEventListener('click', function() {
            // Arguments passed are tab outer, button outer, content outer, button active class, tab active class and clicked button
            changeTab(a, b, c, d, f, this);
          });
        }
      }
    }
  }
Now in above code I declared a function, this function actually starts the tab working. I passed an argument of updated options, so that I can access them in function. Used document.querySelector() to select outer wrap, button wrap and container wrap. Then declared changeTab function, which is described in next.

First changeTab function have last argument b.children[0] which is the first button in button wrap. Means the targeted container is of button 1. Later in the above code, first loop confirms that the given button wrap is actually a child of outer wrap. Then added changeTab function to every button with addEventListener. 

function changeTab(outer, button, content, bactive, cactive, current) {
    // Id for tab
    var currentId = current.hash;
    for (var i = 0; i < outer.children.length; i++) {
      // Works only if content container is under the tab container
      if (outer.children[i] == content) {
        for (var x = 0; x < content.children.length; x++) {
 // Remove active class from all content and hide them all
          content.children[x].classList.remove(cactive);
          content.children[x].style.display='none';
          if (content.children[x] == content.querySelector(currentId)) {
            content.children[x].classList.add(cactive);
            content.children[x].style.display='block';
          }
        }
      }
   // Check if button wrap is under outer wrap
      if (outer.children[i] == button) {
    // Loop on each button
        for (var o = 0; o < button.children.length; o++) {
   // Remove active from all buttons
          button.children[o].classList.remove(bactive);
        }
  // Add button to current button
        current.classList.add(bactive);
      }
    }
  }
changeTab function updates the classes of button and container and hide other containers which are obviously not active. element.hash is used to get value with '#' in href tab. Then a loop to confirm the child of outer wrapper and then one loop for button wrap and other one for content wrap.

Attach Method With Plugin

Every object got properties and methods. Using object.prototype we can access any object properties. These events allow people to access the stuff going on under each instance. object.prototype creates a prototype of an object that holds all the properties of an object or its instance. Example of properties are options in our case.

Tabs.prototype.activeTabId = function (e) {
    var contentWrap = document.querySelector('.tab-content');
    var anyElement = document.querySelector(e);
    for (var i = 0; i < contentWrap.children.length; i++) {
        if (contentWrap.children[i].classList.contains(this.options.activeContainerClass)) anyElement.innerHTML = contentWrap.children[i].id;
    }
}
Above code is an example of prototype in our case. This prototype returns the active tab id, click the button, it will return active tab id, check in demo.

A better approach

ECMAScript 6 got for...of loop that is alternate for:

var x=[2,3,4]
for(var i = 0 ; i < x.length; i++){

}
This could be written as for...of loop:

var x=[2,3,4]
for(let i of x){

}
I didn't used that since no support for IE.

Conclusion

Plugins are possible in Javascript, a bit lengthy and boring because jQuery got complete references for that while no proper Javascript references available. Is there is any better approach to create plugin, send me via email : [email protected] or put some useful link in comments so that I could update this reference for others.
Blogger

2013-2016 Copyright Blogger E\ver . Coded, managed and founded by Mohammad Hamza (@hamzadhamiya) . Hosted on Blogger and fonts used are Raleway and Open Sans.