Easy Setter Functions in jquery
One of the new feature in jQuery 1.4 is setter function. For a while now, you’ve been able to pass a function into .attr() and the return value of that function is set into the appropriate attribute. This functionalilty has now been extended into all setter methods: .css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .before(), .after(), .replaceWith(), .wrap(), .wrapInner(), .offset(), .addClass(), .removeClass(), and .toggleClass(). Addtionally, for the following options, the current value of the item is passed into the function as the second argument: .css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .offset(), .addClass(), .removeClass(), and .toggleClass().
$('a[target]').attr("title", function(i, currentValue){ return currentValue+ " (Opens in External Window)"; }); $("#xx").text(function (i, currentValue) { return currentValue+ "modified by fred"; });
In jQuery 1.32, the attr is defined as follow
attr: function( name, value, type ) { var options = name; // Look for the case where we're accessing a style value if ( typeof name === "string" ) if ( value === undefined ) return this[0] && jQuery[ type || "attr" ]( this[0], name ); //jQuery.attr(this[0], name); else { options = {}; options[ name ] = value; } // Check to see if we're setting style values return this.each(function(i){ // Set all the styles for ( name in options ) jQuery.attr( type ? this.style : this, name, jQuery.prop( this, options[ name ], type, i, name ) ); }); },
But in 1.4.2, it is defined as followed.
attr: function( name, value ) { //the access function is defined in core module return access( this, name, value, true, jQuery.attr ); },
We can see that a protected access function really does the job.
// Mutifunctional method to get and set values to a collection // The value/s can be optionally by executed if its a function // elems is an array // key, value is dictionary pair // exec is an boolean, put it true if you want to call the value as a function // fn is a function used to access the element // passe is usually false, I am not sure it is intention function access( elems, key, value, exec, fn, pass ) { var length = elems.length; // Setting many attributes //if key is complext object like { name: "fred", age: 18 } if ( typeof key === "object" ) { for ( var k in key ) { access( elems, k, key[k], exec, fn, value ); } return elems; } // Setting one attribute if ( value !== undefined ) { // Optionally, function values get executed if exec is true //if value is a function which dyanmically return a true value //and pass is null //and exec is true //then set exec to true //if caller pass is undefined and caller want to evalueate the value function and value is a function exec = !pass && exec && jQuery.isFunction(value); //your callback function is like //function( elem, name, value) //for example //Query.fn.css = function( name, value ) { // return access( this, name, value, true, function( elem, name, value ) { //or function( elem, name, value, pass ) //for example attr: function( elem, name, value, pass ) for ( var i = 0; i length; i++ ) { //fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); //exec means your value to set is need to be determined by the callback functio var elem = elems[i]; var valueToSet; if (exec) { //get the current value first var currentValue = fn(elem, key); //then call the value function to get the new value valueToSet = value.call(elem, i , currentValue); } else { valueToSet = value; } fn(elem, key, valueToSet, pass); } return elems; } // Getting an attribute return length ? fn( elems[0], key ) : undefined; }
jQuery.fn.css method also used this protected method.
jQuery.fn.css = function( name, value ) { //rather call function(elem, name, value) call //access function, and let access function to call back function(elem, name, value) return access( this, name, value, true, function( elem, name, value ) { if ( value === undefined ) { return jQuery.curCSS( elem, name ); } if ( typeof value === "number" && !rexclude.test(name) ) { value += "px"; } jQuery.style( elem, name, value ); }); };