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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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.


May 23, 2012 at 10:10 PM // reply »
1 Comments

Thank you so much for the overriding sample. Ironically, it did not work when I tried to override the html() method, however your *OTHER* sample

http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm

worked great.

Perhaps because the second sample function inside the closure gives up a return value, needed for method changing by JQuery, i.e. the error I received was illustrative:

TypeError: 'undefined' is not an object (evaluating 'c("<span></span>").addClass("ui-dialog-title").attr("id",
e).html(d).prependTo')

I just shamelessly copied your other sample (and brazenly changed it) and it worked great.

Many thanks.


May 28, 2012 at 11:59 PM // reply »
1 Comments

Clear and straightforward, thanks!



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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools