Override core jQuery functions on Element level
Is it possible to override core jQuery functions on Element level, so for an example, i want to override val() function only on one <select> element.
if i do something like this
var element = $('select');
var old_val = element.val;
element.val = function开发者_运维知识库 () {
console.log('The new val');
return old_val.apply(this, arguments);
}
element.val(19);
it works as expected, but as soon as i address the same field with new jQuery instance
var element = $('select');
element.val(19);
it stops working because we have new instance of jQuery object. if i fiddle with $.fn.val function i change that behavior for all objects who support val function, which is a bit to much for me.
Any help will be appreciated. Thank you.
I made this jquery extension for doing just what you're talking about:
// overrides a method thats supposed to be called on a single node (a method like val)
$.fn.overrideNodeMethod = function(methodName, action) {
var originalVal = $.fn[methodName];
var thisNode = this;
$.fn[methodName] = function() {
if (this[0]==thisNode[0]) {
return action.apply(this, arguments);
} else {
return originalVal.apply(this, arguments);
}
};
};
Bonus over Dave's answer - you don't have to pollute the jquery data namespace or worry about someone overwriting that key
Based on answer by sdleihssirhc but modified to only apply to the previously matched element(s), since you said "only on one <select> element".
element.data('custom_val', function() {
console.log('The new val');
});
$.fn.old_val = $.fn.val;
$.fn.val = function () {
var custom_val = this.data('custom_val');
if (custom_val) {
return custom_val.apply(this, arguments);
} else {
return this.old_val.apply(this, arguments);
}
};
This little snippet allows to override jQuery methods.
I find @BT answer quite bad as it creates extra callback every time function is used. So if you'll apply it to 1000 elements, 1000 functions for EVERY val()
are called!
My overrideNodeMethod
can be applied to as many elements as many times as you want. It basically checks hasOverriddenMethod
data
var originaljQueryMethods = {};
for(var method in $.fn){
originaljQueryMethods[method] = $.fn[method];
};
$.fn.callOriginalMethod = function(method, args) {
return originaljQueryMethods[method].apply(this, args);
};
$.fn.overrideNodeMethod = function(method, callback) {
var dataKey = "hasOverriddenMethod." + method;
$(this).callOriginalMethod("data", [dataKey, callback]);
$.fn[method] = function() {
var callback = $(this).callOriginalMethod("data", [dataKey])
if (callback) {
return callback.apply(this, arguments);
}
return $(this).callOriginalMethod(method, arguments);
};
};
Every jQuery object includes a selector
property, which contains (duh) the original selector that was used to get the elements (I haven't really worked with it at all, so I'm not sure what happens to it as you go through a chain of methods).
So you could wrap the val
method in a function that checks the selector
property, and then decides whether to use your function or the original. It would look something like this:
$.fn.old_val = $.fn.val;
$.fn.val = function () {
if (this.selector === 'select') {
console.log('The new val');
}
return this.old_val.apply(this, arguments);
};
You basically had this before, I'm just tweaking it so it will apply to all new jQuery instances.
(Also, this is pretty simplistic on it's own; you'll want to modify/enhance it accordingly.)
Yeah this a great question. I'd never try this thing.
Let's go:
Before we start we should copy the default val-function to another place:
jQuery.fn.oldval = jQuery.fn.val;
I would write a function global to catch the val() function:
jQuery.fn.val = function(value) {
var t = jQuery(this);
if(t.get(0)) {
//Check for overwritten function
var func = jQuery.data(t.get(0), 'val-function');
if(jQuery.isFunction(func)) {
return func(value);
}
}
//Use old function
return jQuery(this).oldval(value);
};
After that you can set a function to your Element-Data with:
var element = jQuery(...);
jQuery.data(element.get(0), 'val-function', function(value){
/* Your Function here */
});
I don't know if this works. Try it. It's only from my brain.
精彩评论