Sunday, November 18, 2012

Extending jQuery functions

When developing with jQuery or any other JavaScript framework, sometimes we want to do more with the framework core functions. For example, many times, when I'm adding or removing a class to/from a jQuery element I want to call a function. If I'll call a function every time I'm adding or removing classes right after the addClass or removeClass it will be hard to maintain the code.

In this post I'll show how to expand jQuery core functions, as an example I will demonstrate how to add addClass and removeClass events to each jQuery element.

Let's start by creating a closure to avoid variable conflicts:
(function(){
    // code goes here...
})();

Now, before the core functions override, we need to save them in order to call them later inside the expanded function
(function(){
    // saving the core functions
    var coreAddClass = jQuery.fn.addClass;
    var coreRemoveClass = jQuery.fn.removeClass;
})();

Core functions saved, now we can override them
(function(){
    // saving the core functions
    var coreAddClass = jQuery.fn.addClass;
    var coreRemoveClass = jQuery.fn.removeClass;

    // overriding the addClass function
    jQuery.fn.addClass = function(){

    }

    // overriding the removeClass function
    jQuery.fn.removeClass = function(){

    }
})();

If you will run the code we wrote so far and try to $().addClass() or $().removeClass() nothing will happen. The next step is to add our new logic to the functions and then to call the core functions so we will keep the original behaviors
(function(){
    // saving the core functions
    var coreAddClass = jQuery.fn.addClass;
    var coreRemoveClass = jQuery.fn.removeClass;

    // overriding the addClass function
    jQuery.fn.addClass = function(){
        // every time the addClass function is called
        // for this $element, trigger the addClass event
        $(this).trigger('addClass', arguments);

        // calling the core function
        coreAddClass.apply(this, arguments);
    }

    // overriding the removeClass function
    jQuery.fn.removeClass = function(){
        // every time the removeClass function is called
        // for this $element, trigger the removeClass event
        $(this).trigger('removeClass', arguments);

        // calling the core function
        coreRemoveClass.apply(this, arguments);
    }
})();

By applying the core function at the end of the function we are able to keep the original behavior of the core.

Simple client to test the code:
<!DOCTYPE html>
<html>
    <head>
        <title></title>
  
        <script type="text/javascript" src="jquery.min.js"></script>
        <script type="text/javascript" src="jquery.events.js"></script>
        <script type="text/javascript">
            $(function(){

                // add event listener to the element addClass event
                $('.cube').on('addClass', function(e, className){
                    console.log(e);
                    console.log(className);
                });

                // add event listener to the element removeClass event
                $('.cube').on('removeClass', function(e, className){
                    console.log(e);
                    console.log(className);
                });
    
                $('button').on('click', function(){
                    // toggle a class on the element, the events are fired
                    $('.cube').toggleClass('color');
                });
            });
        </script>
  
        <style type="text/css">
            .cube{width:100px;height:100px;background:yellow;}
            .color{background:red !important;}
        </style>
    </head>
    <body>
        <div class="cube"></div>
        <button>toggle red</button>
    </body>
</html>