Question
I'd like to know the best way I can wrap the jQuery function while retaining all functionality. Essentially I want to call $('#someId')
but have it operate as $('#' + id + 'someId')
by wrapping the function, modifying the arguments, and passing it through to the original jQuery function.
Motivation
I have a section of JS that will reuse the same variable winId
which is concatenated and passed to jQuery. Instead of writing
$('#' + winId + 'someId').html();
$('#' + winId + 'someOtherId').css();
...
$('#' + winId + 'someThirdId').text();
throughout the whole file, I want to wrap the jQuery function so I can just call
$('#someId').html();
$('#someOtherId').css();
...
$('#someThirdId').text();
and and have winId
added in before passing through to $
.
My attempt
Here's what I'm thinking as a wrapper:
(function() {
var fn = $;
return $ = function() {
for ( var i = 0; i < arguments.length; i++ ) {
if ( typeof arguments[i] == 'string') {
arguments[i] = /* code to add in winId, omitted */
}
}
return fn.apply( this, arguments );
}
})();
This works great, except that obviously none of the methods like $.ajax
are available:
Uncaught TypeError: Object function () {
for ( var i = 0; i < arguments.length; i++ ) {
if ( typeof arguments[i] == 'string' ) {
arguments[i] = /* code to add in winId, omitted */
}
}
return fn.apply( this, arguments );
} has no method 'ajax'
Note: I know I could copy the object over using jQuery.extend($, jQuery)
, but I'm interested in a more elegant solution than that if possible.
Here's a different implementation:
(jQuery.fn.init = (function (init) {
return function (selector) {
if (typeof selector === 'string' && selector[0] === '#') {
arguments[0] = selector.replace('#', '#prefix_');
}
return init.apply(this, arguments);
};
})(jQuery.fn.init)).prototype = jQuery.fn;
$(function () {
console.log($('#test').length);
console.log($.ajax);
});
EDIT: Followup question: How can I apply this only within a closure? For example, within an object.
Perhaps with functions that allows to add named decorators and remove them, something like:
HTML
<div id="prefix_test"></div>
JS
var decJQ = (function (decJQ, $) {
var decorators = {},
init = $.fn.init;
($.fn.init = function () {
for (var k in decorators) {
if (decorators.hasOwnProperty(k)) {
arguments = decorators[k].apply(this, arguments);
}
}
return init.apply(this, arguments);
}).prototype = $.fn;
return $.extend(decJQ, {
decorate: function (name, fn) {
decorators[name] = fn;
},
undecorate: function (name) {
delete decorators[name];
}
});
})(window.decJQ || {}, jQuery);
decJQ.decorate('idPrefix', function (selector) {
if (typeof selector === 'string' && selector[0] === '#') {
arguments[0] = selector.replace('#', '#prefix_');
}
return arguments;
});
$(function () {
console.log($('#test').length); //1
decJQ.undecorate('idPrefix');
console.log($('#test').length); //0
});
EDIT 2: You could also go for something extremely simple, such as:
(function ($) {
//use $ which has been wrapped
})(function () {
//do some manipulations
return jQuery.apply(this, arguments);
});
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments