— Tech+Life+Music

Archive
Tag "jquery extend"

One of the questions I normally get from jQuery learners (aside from why the hell .bind() doesn’t work on dynamically-added HTML elements) is how to write a jQuery plugin. So for this article, I thought I’d introduce a fairly simple step-by-step walkthrough of creating a jQuery plugin that allows us to make something like this really quickly:

Doing this using vanilla jQuery

Of course, you can pretty much do this just by using plain jQuery, just as you would do with most other jQuery functionality. Something like the following would suffice:

// yeap, I know that this code can be optimized a big deal.
jQuery(function($){
 
    // we create two DIVs which form the two parts of our message box
    var $header = $('<div/>').addClass('header').text('Some header'),
        $message = $('<div/>').addClass('message').text('Some message');
 
    // we add the click handler that makes the message slide up and down
    $header.click(function() { $message.slideToggle('fast'); });
 
    // finally, we stick those two DIVs inside some other element
    $('#foo').append($header).append($message);
 
});

With something like that, you’ve pretty much managed to accomplish the same thing.

However, if we want to be able to reuse that piece of code on several other elements, it’d be a better idea to write out that whole jQuery logic into a plugin, so we can just call on it whenever we want.

The basics of extending jQuery

jQuery exposes two kinds of ways to extend it: one using the $ namespace, and the other using $.fn.

Extending the plain $ object allows you to define new utility functions. Adding a new utility function is as easy as just naming a new property:

// creating the "say" utility function
$.say = function (message) {
    alert (message);
};

We can then use that much like any other function by calling $.say('Bros before hoes.');, and it’ll behave as you’d expect it to.

An arguably more powerful way of extending jQuery is extending $.fn, which allows you to create new functions that act on wrapped objects (like, for example, .addClass()). You create new wrapper methods in much the same way you create utility functions:

$.fn.foobar = function () {
    this.text('foobar');
    return this;
}

Inside a new wrapper function, the this object is set to the jQuery wrapped set that the method was called on. So if $('#foo').foobar(); is called, then this inside foobar() is set to $('#foo'). This way, you can manipulate the elements as you see fit.

One of the things you should make a mental note of is to return the this context after the function resolves, so that your new wrapper method is compatible with jQuery chaining. (That is, you can do something like $('#foo').foobar().addClass('bar');.)

Changing our original jQuery code into a plugin

Now that we’ve got the basics out of the way, it should be fairly straightforward to rewrite our code above into a bit of jQuery plugin functionality. Calling our new method slidingBox() and applying the necessary changes in code, we get something like:

(function($){
 
    $.fn.slidingBox = function (header,message) {
 
        var $header = $('<div/>').addClass('header').text(header),
            $message = $('<div/>').addClass('message').text(message);
 
        $header.click(function() { $message.slideToggle('fast'); });
 
        return this.append($header).append($message);
    };
 
})(jQuery);

With that out of the way, we can then use that just by calling something like $('#foo').slidingBox('This is my header.','This is my message.');. With a bit of CSS styling, you’re more or less ready to go!

If you want a more interactive way of demo-ing the code discussed in this article, or if you want to tinker around with ready-made code a bit, then feel free to wreak havoc on a jsFiddle I prepared especially for this article. It’s got ready jQuery code, and some CSS to boot.

Read More

It’s not unusual to cache reusable components in your pages onto variables so that you don’t have to reselect / reevaluate them every single time you have to do something with them.

Let’s say I had a DIV element that I can append paragraphs onto. (Every) Javascript developer worth his/her salt performs some bit of namespacing to the effect of:

<div id="foo"><!-- BLAH --></div>
var app = {
    foo : $('#foo')
};

This way, whenever I’d want to reference that DIV again, I’ll just have to call it via app.foo. I’m actively refraining from polluting the global namespace with a slew of variables for all the elements I want cached, and I have a ready jQuery element that doesn’t need re-selection every time I want to use it.

Adding in functionality

Now, say that I want to add in the functionality to actually add in the paragraphs into my DIV. I can achieve that by doing something like:

var addParagraph = function (text) {
    var myParagraph = $('<p></p>').text(text);
    app.foo.append(myParagraph);
};

… which is perfectly valid since app.foo is, in itself, a valid jQuery object. Improving on that a bit, I’d personally stick that function into the namespace I created prior, so that I don’t add unnecessary global objects.

var app = {
    foo : $('#foo'),
    addParagraph : function (text) {
        var myParagraph = $('<p></p>').text(text);
        app.foo.append(myParagraph);
    } 
};

Making it even better

That’s good. But if you’re a stickler for code (as I am), you’ll probably be itching to structure the code so that app.foo owns the addParagraph function. It makes better sense to have a function that acts on an object alone to be within scope of said object. I’ve got you.

One way to go about it is something like :

app.foo.addParagraph = function (text) {
    var myParagraph = $('<p></p>').text(text);
    this.append(myParagraph);
};

… and that on its own isn’t exactly bad, as you’re getting exactly what you want done. However, the way I’d recommend it most of the time is by using jQuery’s $.extend() function.

$.extend(app.foo, {
    addParagraph : function (text) {
        var myParagraph = $('<p></p>').text(text);
        this.append(myParagraph);
    }
});

$.extend() isn’t something that a lot of jQuery programmers bother with (at least, I think so), but it accomplishes more or less exactly the same thing. So why, then, should I use the $.extend()?

  1. It’s cleaner and easier to add in multiple functionalities at once.

    If I wanted to add in more stuff, like add, edit and remove paragraph functionalities into my object, my code would most probably end up a mess. Not that it’s not possible, but it’s a bit of a maintainance nightmare to have to code something like

    app.foo.add = function () {};
    app.foo.edit = function () {};
    app.foo.remove = function () {};
    // ... some more functions

    I’d rather see something like

    $.extend(app.foo, {
        add : function () {},
        edit : function () {},
        remove : function () {}
    });

    … and since we’re technically working with a plain JSON object as $.extend()‘s second parameter, it’s perfectly valid to go this path :

    var paragraphFunctions = {
        add : function () {},
        edit : function () {},
        remove : function () {}
    };
     
    $.extend(app.foo, paragraphFunctions);

    Wouldn’t you agree that that’s much easier to look at and take care of?

  2. It’s easier to work with multiple components that share the same functionality.

    Not only is it easier to slap on multiple functionalities on one object, but it’s also easier to slap on the same functionalities onto multiple objects.

    If I had two of those DIVs, then traditionally I’d have to do something like this:

    var app = {
        foo : $('#foo'),
        bar : $('#bar')
    };
     
    app.foo.add = function () {};
    app.foo.edit = function () {};
    app.foo.remove = function () {};
     
    app.bar.add = function () {};
    app.bar.edit = function () {};
    app.bar.remove = function () {};
     
    // yeap, I know that that's kind of a stretch

    A more convenient method would be to cache a JSON object with the common functionalities, and use $.extend to slap those onto the relevant components.

    var paragraphFunctions = {
        add : function () {},
        edit : function () {},
        remove : function () {}
    };
     
    $.extend(app.foo, paragraphFunctions);
    $.extend(app.bar, paragraphFunctions);

    Of course, you could also utilize Javascript prototyping at a lower level to achieve the same thing, but this is a somewhat quicker (and less complex) way of doing that.

You can check out a very rudimentary example of making it all work over on jsFiddle.

Read More