Ask Ben: Overriding Core jQuery Methods

Posted June 30, 2009 at 2:06 PM by Ben Nadel

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:

  • <!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.




Reader Comments

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

Nice. Pretty nice Ben.


Jul 1, 2009 at 8:13 AM // reply »
10,640 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 »
10,640 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 »
10,640 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 »
10,640 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 »
10,640 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 »
10,640 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 »
10,640 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 »
10,640 Comments

@CasperJ,

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


Jan 27, 2010 at 10:07 AM // reply »
2 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 »
10,640 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.


May 18, 2010 at 9:09 AM // reply »
1 Comments

Hi Ben,

Thanks for this simple tips. One more suggestion, when calling a parent function, always add a return to it:

return originalHideMethod.apply( this, arguments );

Otherwise, this break the jQuery chain. Doing something like:
$('#foo').hide().remove(); break after the hide...


May 18, 2010 at 8:38 PM // reply »
10,640 Comments

@David,

Ah, most excellent point. I would say take that to the next level and actually always use a return statement when using call() or apply(). Probably always the best way to make it future-proof.


Sep 22, 2010 at 11:47 PM // reply »
1 Comments

I tried to override the inArray method using the above example without success.

alert(jQuery.fn.inArray) was [undefined] but alert(jQuery.fn.html) returned the function source for the html method.

I'm not sure what I'm missing here...


Sep 23, 2010 at 10:09 PM // reply »
10,640 Comments

@Ben,

The inArray() method is part of the core root jQuery object, not a collection method. You'll need to reference off the main jQuery object:

alert( jQuery.inArray )

Notice that I left out ".fn" which is the collection of methods that get used for the jQuery instances.


Bob
Jan 20, 2011 at 3:28 PM // reply »
1 Comments

Thanks for this! I was already doing most of this, but couldn't get things to work. I didn't know about .apply( ) before now! Thanks!


Mar 30, 2011 at 10:38 PM // reply »
1 Comments

That is awesome!

One nitpick, put "return" before
originalRemoveMethod.apply( this, arguments );


Mar 30, 2011 at 10:43 PM // reply »
10,640 Comments

@Bob,

Glad to help clarify that. apply() and call() are awesome parts of Javascript.

@Barry,

Ahh, good catch! I think I became much better about my return statements once I really got into plugin development.


Nov 25, 2011 at 1:12 PM // reply »
1 Comments

You should add "return" to your remove() override example.
I just found a piece of code which was built using remove() override, and it messed up jQuery UI animations - elements just disappeared.

I changed the code to the following:
return originalRemoveMethod.apply(this, arguments);

and now jQuery UI works fine.



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »
Feb 9, 2012 at 10:29 PM
Learning ColdFusion 9: Application-Specific Data Sources
@Ben, No offence, but if people were really wanting advanced features they would be using a platform like ASP.NET MVC. CFML is so structurally compromised as a tag-based scripting language that ... read »
Feb 9, 2012 at 10:03 PM
Subversion - Cleanup Failed To Process The Following Paths
@Leviaguirre, do you still have problems with this? ... read »