jQuery attr method can set click handler and inner text
Asked Answered
C

3

8

Reading jQueryUI dialog code, I've found out, jQuery .attr() method has some undocumented behavior:

<button id="btn1">1</button>
<button id="btn2">2</button>

$(function() {
    var props = {
        text: 'Click it!',
        click: function () {
            console.log('Clicked btn:', this);
        }
    };

    $('#btn1').attr(props, true);    // Changes #btn1 inner text to 'Click it!' 
                                     // and adds click handler
    $('#btn2').attr(props);          // Leaves #btn2 inner text as it is and fires 
                                     // click function on document ready
});
  • Can you explain me how it works? Why should I set true as the second argument after map of attribute-value pairs?
  • Can I use this feature in my projects safely?
Cinchonism answered 18/10, 2012 at 12:39 Comment(2)
I would suggest that using attr() to create click handler is an unsupported method in JQuery. There are many things that may work using the framework, but if undocumented don't trust them, they may break in future upgrades. Have seen jQuery dev team express this same philosophy in their support forumSharasharai
The reason, I've posted this question was that I couldn't understand, why click handler fired before it was applied. Please, watch this jquery.ui.dialog.js L371Cinchonism
R
3

I'm guessing slightly here because I'm unfamiliar with the jQuery source. jQuery.attr calls jQuery.access, and the comment above the jQuery.access function reads:

// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function

Upon further investigation, the text() function also calls jQuery.access:

    attr: function( name, value ) {
        return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
    },
    .........
    text: function( value ) {
        return jQuery.access( this, function( value ) {
        ......
    },

You're using attr to set text and event handlers, which is not what attr is for. However they all seem to be using the same function to get the job done, so the use of undocumented parameters is just incidentally giving you the expected behavior.

I would consider it unreliable to rely on undocumented behavior to accomplish what you're trying to do here, as any future upgrade of jQuery could break your code.

Rothstein answered 18/10, 2012 at 12:59 Comment(2)
also, if you're going to use an undocumented feature, you should at minimum document this usage, which would take more typing than simply using separate click() & text() methodsTobitobiah
It's also worth mentioning that it's unclear whether binding events like this would work with dynamically-added DOM elements, so you could lose your bindings on new objects. Much better to use .on() for your event handling, rather than setting it on an object-by-object basis, like this.Shortly
Y
2

Looking at the jQuery 1.8.2 code, the true parameter eventually arrives in the variable pass at a line that says:

exec = pass === undefined && jQuery.isFunction( value );

which if set, tells jQuery to check the check the value belonging to the key, and if it's a function, call it immediately. Hence click: function(...) will call that function, not register that function.

This appears to be how the .method(function() { ... } versions of various jQuery functions work, i.e. those where instead of passing a specific value for a property, you pass a function which is itself passed the original value, and whose return value is assigned to the relevant property.

Can I use this feature in my projects safely?

I wouldn't, not until it's documented.

Yogurt answered 18/10, 2012 at 13:0 Comment(0)
S
0

This is an interesting one. I can't pretend to tell you /why/ it works, this way, and I think there even might be reason to submit this as a bug report to jQuery, because the behavior that they document is not coming out as I'd expect.

On this page, the following quote appears toward the bottom: http://api.jquery.com/attr/

"Note: If nothing is returned in the setter function (ie. function(index, attr){}), or if undefined is returned, the current value is not changed. This is useful for selectively setting values only when certain criteria are met."

This led me to do some playing around on jsFiddle: http://jsfiddle.net/mori57/GvLcE/

Note that, contrary to their documentation, Cases 8 and 9 return either null or nothing. Looking at what Alnitak mentioned, it seems to makes sense, as their test /actually/ is only validating that it /is a function/ not what that function returns (.isFunction should only ever return true/false, which is different from saying that the value returned is true/false).

In the end, however, I'd agree with both Alnitak and bcoughlan that this is not functionality you should rely on, though I'd add that, in addition to it being unstable because it may be changed in future releases of jQuery, it is also bad practice to rely on hacks that are reliant on undocumented features because future developers of the code you write today (and that includes you, in 2-4 months!) could very easily forget that is there, or why it's set that way. Far better to be explicit, and use functionality as documented, so that you're clear to yourself and others what your code is intended to do.

Shortly answered 18/10, 2012 at 13:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.