Ask Ben: Overriding Core jQuery Methods

Posted June 30, 2009 at 2:06 PM

Tags: Javascript / DHTML, Ask Ben

Is there a way to overload the included remove() function in jquery? Possibly a separate js file? For example we are using the min version and it would be cool to not have to add this in each time we upgraded to a new version that has come out?

jQuery is such a well thought out, powerful Javascript library, that it actually uses itself to build itself. What I mean by that is that many of the methods provided by the jQuery library are actually built internally as plugins to the jQuery architecture. When you start to think about the methods in this way, it is a small leap to see that we can override a given jQuery method by simply creating a new plugin of the same name.

 
 
 
 
 
 
 
 
 
 

Before I demonstrate this, I want to just prefix this with saying that by overriding a core library method, you do run the risk of creating problems when upgrading the library. If you override a method and then don't update it in parallel with the library updates, you might retain bugs that subsequent releases of the library have fixed. That said, in the following demonstration, I am going to override the remove() method by creating a new "remove" plugin:

 Launch code in new window » Download code as text file »

  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <title>Overriding jQuery Methods</title>
  • <script type="text/javascript" src="jquery-1.3.2.js"></script>
  • <script type="text/javascript">
  •  
  • // Create a closure so that we can define intermediary
  • // method pointers that don't collide with other items
  • // in the global name space.
  • (function(){
  • // Store a reference to the original remove method.
  • var originalRemoveMethod = jQuery.fn.remove;
  •  
  • // Define overriding method.
  • jQuery.fn.remove = function(){
  • // Log the fact that we are calling our override.
  • console.log( "Override method" );
  •  
  • // Execute the original method.
  • originalRemoveMethod.apply( this, arguments );
  • }
  • })();
  •  
  •  
  • // When DOM is ready, initialize.
  • $(function(){
  •  
  • $( "a" )
  • .attr( "href", "javascript:void( 0 )" )
  • .click(
  • function(){
  • // Remove the target link.
  • $( this ).remove();
  •  
  • // Cancel default event.
  • return( false );
  • }
  • )
  • ;
  •  
  • });
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • Override a jQuery Method
  • </h1>
  •  
  • <p>
  • <a>Remove Me 1</a>
  • <a>Remove Me 2</a>
  • <a>Remove Me 3</a>
  • </p>
  •  
  • </body>
  • </html>

In the above code, we are creating our new "remove" plugin inside of its own closure. This is done so that we can create an intermediary variable - a reference to the original remove() plugin - without colliding with other variables in the global name space. Once we have this pointer, we then override the core remove() method with our new jQuery.fn.remove method. For testing purposes, we are simply logging a note that we are in the new method and then executing the original method.

Of course, if you wanted to override the core version, you wouldn't turn around and call apply() on it - you'd actually move the original remove() logic into our new plugin and then update it as necessary. In this way, you can fully override the core method with whatever logic you see fit. I hope this helps.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page




Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Jun 30, 2009 at 7:21 PM // reply »
15 Comments

Nice. Pretty nice Ben.


Jul 1, 2009 at 8:13 AM // reply »
7,463 Comments

@William,

Thanks my man. I've never actually done this in production, but it seems straightforward enough.


Jul 1, 2009 at 10:31 AM // reply »
20 Comments

That's pretty cool. You can even take it a step further and just use a copy of the original jQuery function object to be able to replace multiple functions all at once. I borrowed the clone function from here, http://my.opera.com/GreyWyvern/blog/show.dml/1725165. Then I used it to make a copy of jQuery's functions so that I can call any of the original methods in my new extended version.

Object.prototype.cloneObject = function() {
var newObj = (this instanceof Array) ? [] : {};
for (i in this) {
if (i == 'cloneObject') continue;
if (this[i] && typeof this[i] == "object") {
newObj[i] = this[i].cloneObject ();
} else newObj[i] = this[i]
} return newObj;
};

(function(){
// Store a reference to the original remove method.
var SuperJQ = jQuery.fn.cloneObject();

// Define overriding method.
jQuery.fn.extend({
remove: function(){
// Log the fact that we are calling our override.
console.log( "Override Remove method" );

// Execute the original method.
return SuperJQ.remove.apply( this, arguments );
},
parent: function() {

// Log the fact that we are calling our override.
console.log( "Override Parent method" );

// Execute the original method.
return SuperJQ.parent.apply( this, arguments );

}
})
})();


Jul 3, 2009 at 9:02 AM // reply »
7,463 Comments

@Anthony,

Nice suggestion. Using the extend() method is definitely a quality choice, especially if you have more than one method to set / override at a given time.


Sep 16, 2009 at 1:50 PM // reply »
1 Comments

thanks, this was very useful to me.

Additionally, I will add. (This has nothing to do with your post but relates to my specific situation)

if someone is trying to apply a override for a specific situation
and needs to compare objects, it wont work. (in jQuery)

Apparently jQuery Objects are 'never' identical. (even if they appear to be)

e.g this:
if (this === jQuery('td#elem_pager')){ // will never evaluate to true

// or this of course
if (this == jQuery('td#elem_pager')){ // will never evaluate to true

One will need to use an attribute (or something) such as:

if (this.attr('id') == jQuery('td#elem_pager').attr('id')){ //can evaluate to true
// override core method, re: cant modify 3rd party libs
apply_specific_functionality;
}
else {
// Execute the original method.
originalRemoveMethod.apply( this, arguments );
}

I apologize if this is obvious/rudimentary info, please correct me
if it is incorrect as well.

I also realize this is not good approach as it's not really scalable,
however it will work in my situation for now


Sep 21, 2009 at 8:23 AM // reply »
7,463 Comments

@Dwright,

Interesting. I have never tried to compare two jQuery objects, but I guess that makes sense since a new jQuery object is created for each selector.


Nov 23, 2009 at 10:28 AM // reply »
5 Comments

Hello,
I am trying to use jquery - I am a new at this.
I want to override just one function showLabel in jquery.Validate that is used by xVal.jquery.validate
Is there any simple way to do it?
I've downloaded some inheritence plugin but couldn't implement the sample that i've found to it.
Nevertheless i do need all the functionality to stay the same way , and the showLabel is still being called in jquery.Validate . How can i resolve my situation without werighting all the jquery framework ? :)


Nov 23, 2009 at 1:34 PM // reply »
7,463 Comments

@Gregory,

Overriding methods can get a bit tricky inside of a jQuery plugin due to the way in which Javascript methods are scoped. When you define a method, it is lexically scope, meaning it can refer to variables available at the time of the method definition.

When it comes to Javascript inheritance, this type of scoping can cause problems if other methods in the object refer to the method in a way that you could not override (ie. not referencing it via the "this" scope).

The easiest thing for you to do would probably be to create a duplicate of the plugin and go in an update the method manually?


Nov 24, 2009 at 2:05 AM // reply »
5 Comments

But wan't it create problems when we upgrade to more progressive version of the plugin?
We would have to analyse all our changes from the beggining before changing the plugin , and if we are talking about a long period it will be hell..
So you don't see any way to override a specific function inside a workflow of a plugin ? Maybe some other way that I have not think about?
Won't extend work somehow in this situation ?
Thanks for the quick reply.


Nov 24, 2009 at 5:01 AM // reply »
5 Comments

I've seen your presentation on jQuery . It's very informative . Thanks !
Do you think that , as you explain in your presentation I could Extend the showLabel function of the jquery.validate and how can i trap the specific inner anonymous function into a var object so i could weright it . And also is there going to be a conflict if i extend the showLabel calling the extension the same name?
thanks a lot for your time and great presentation :)


Nov 24, 2009 at 7:54 AM // reply »
7,463 Comments

@Gregory,

You could certainly try to extend the main plugin; but, it depends on how it is wired internally. Some plugin authors go a bit crazy (IMO) with object literals and how things are defined - and it makes it hard to extend in an elegant way.

That said, you should definitely open her up and see what's going on inside; it might be a good place for extension.


Nov 24, 2009 at 9:00 AM // reply »
5 Comments

@Ben Nadel,

thanks for the reply.

do you have some kind of sample for this kind of thing?

did you work with xVal ?


Nov 26, 2009 at 9:43 AM // reply »
7,463 Comments

@Gregory,

Beyond this post, I don't really have much in the way of examples about this.


Dec 21, 2009 at 8:20 PM // reply »
1 Comments

I think that using this methodology to inject debugging output as you have here is a great tool and a good idea. Aside from that, I would be leery about overwriting core functionality in a production environment.

Changing the core functionality of a library that is so often used in tandem with multiple plugins is an unstable idea to me.

It may be possible to exactly mimic the interface and behavior of the core function while at the same time adding in your own functionality; however, when the core library updates there's always the chance that you'll be revisiting your overwritten method.


Dec 22, 2009 at 8:19 AM // reply »
7,463 Comments

@Justin,

It really comes down to how you override the given method. As long as you pass on all given arguments and return the resultant return value, what you do in between shouldn't really matter. The only real problem could come in if other sections of your code somehow only have access to the original method.


Dec 22, 2009 at 8:49 AM // reply »
5 Comments

I've done inheritance for inner function of some plugin , during using xVal.
It is really simple , after you get the point -
http://2bhere4u.blogspot.com/2009/12/inheritance-in-jquery.html


Jan 1, 2010 at 3:42 PM // reply »
1 Comments

Hi Ben,

I'm really hope you can help me on this one. I'm trying to override some of the basic functions of jQuery.

What I want is to for example hide some extra fields when a given type of
field is hidden. If you for example tries to hide #bar and #bar has a
css-class of type "foo" then it should also hide #bar_img.

(function() {
var originalHide = jQuery.fn.hide;
jQuery.fn.hide = function() {
this.each(function() {
if (this.className == 'foo')
originalHide.apply( jQuery('#' + this.id + "_img") );
originalHide.apply(this, arguments);
});
return this;
};

})();

Any help is highly appreciated

Thanks and happy new year!
//Casper


Jan 4, 2010 at 9:47 AM // reply »
7,463 Comments

@CasperJ,

Is this breaking? At a cursory glance, it appears to be correct.


Jan 27, 2010 at 10:07 AM // reply »
1 Comments

Hi Ben,
I have a wierd situation. I'm working in a very huge jQuery based project. Functionally, everything is almost done, but now I have few generic requirements to be implemented across all screens. For this, instead of changing all .js files (which are around 500 in number), I was thinking to override $(document).ready function. Do you think this will be a good idea? I think rework would be less, but am not sure of side effects. What do you say?

Here's my implementation:
(function() {
var originalReady = jQuery.fn.ready;
$.fn.extend({
ready: function() {
console.log('custom ready');
originalReady.apply(this, arguments);
}
});
})();


Jan 28, 2010 at 10:52 PM // reply »
7,463 Comments

@Krishna,

I don't think there's anything inherently wrong with this; I guess it just depends on how you're going to use it.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 10, 2010 at 1:35 PM
Project HUGE: Dig Deep Fitness iPhone App And Huge In A Hurry
I can't find the app in the iphone store. Where can I get it? P.S. Big fan of the blog, Ben! ... read »
Mar 10, 2010 at 12:33 PM
(CF)JSON - My Own ColdFusion Version For AJAX
Thanks, Ben! I was banging my head against this for a bit - you've saved me a flat spot on my forehead. ... read »
Mar 10, 2010 at 12:24 PM
How Do You Use The ColdFusion CFParam Tag?
@prims, You can use CFParam to param any type of variable in ColdFusion. ... read »
Mar 10, 2010 at 12:23 PM
How Do You Use The ColdFusion CFParam Tag?
Hi Ben, Can we use cfparam in session scope? Thanks ... read »
Mar 10, 2010 at 11:47 AM
Using Base64 Canvas Data In jQuery To Create ColdFusion Images
This is awesome. Is there a way to implement this on any other touchscreen device, Example BB Storm? ... read »
Mar 10, 2010 at 11:09 AM
Dynamic ColdFusion Variables Via Quoted Naming
@Jim, Awesome. ... read »
Mar 10, 2010 at 11:04 AM
Using Base64 Canvas Data In jQuery To Create ColdFusion Images
@Ryan, I have not seen that - thanks for posting it here. I'll be sure to check it out. ... read »
Mar 10, 2010 at 11:01 AM
Dynamic ColdFusion Variables Via Quoted Naming
Thanks Ben, that's sorted my problem out. Many thanks Jim ... read »