Bug Tracker

Opened 13 years ago

Closed 13 years ago

Last modified 8 years ago

#821 closed enhancement (wontfix)

jQuery.fn.add does not add elements to current jQuery object

Reported by: p.aiello@… Owned by:
Priority: minor Milestone:
Component: core Version:
Keywords: Cc:
Blocked by: Blocking:

Description

if I have a jQuery object 'jq' and a DOM element 'element', and I call (element is enclosed in an array: see bug #806):

jq.add([element]);

the element is NOT added to jq (as in jQuery 1.0), but to a newly created jQuery object which is returned in place of the 'this' object; while it does not break the method chaining, it breaks all code which assumes that after a call to the add method of some jQuery object, that object contains the added element(s)

NOTE: in the documentation, is not explicitly stated when a method returns the same object, and when ia new jQuery object is returned (requiring a call to the end method to restore the previous context); in my opinion this is an important issue which should be clearly documented. Anyway, in the case of the add method, I think it should return the same object, for compatibility and to keep an intuitive behaviour.

Change History (6)

comment:1 Changed 13 years ago by Dave

The consensus from mailing list questions was that people did not expect jq1 to be touched in situations like this:

 var jq1 = $("p");
 var jq2 = jq1.find("a");

The 1.1 behavior ensures they won't be surprised. In 1.1 you can do this to get the equivalent of the 1.0 behavior:

 var jq1 = $("p");
 var jq2 = jq1 = jq1.find("a");

For the .add case, just do this:

 jq = jq.add([element]);

comment:2 Changed 13 years ago by joern

Resolution: worksforme
Status: newclosed

jQuery now takes the fully functional approach, that is, no method modifies the object on which the method is called (though it may modify the underlying objects, eg. DOM elements).

That could be added as a "general contract" to the reference documentation.

comment:3 Changed 13 years ago by p.aiello@…

Resolution: worksforme
Status: closedreopened

There is a fundamental difference between the find method and the add method: when I use find, it is implicit that I don't want to perform an operation on the method owner, but I want to select a different element set from that of the called object, so it is natural that the method returns a new object. But when I call the add method, I want to add an element to *that* object on which I call the method, not to another object. This is a context like that in which I discovered the problem:

var jq = $('#someDiv');

for (var i = 0; i < someArray.length; i++) {

if (anything) {

jq.add(someElement);

}

}

Obviously, there are easy workarounds for that, but the point is that this behaviour is completely counterintuitive, and therefore highly error prone. It is against any logic and any object oriented principle, that calling an add method on object A, the passed objects are added to object B and not to object A.

In my opinion is very important to clearly distinguish the different types of operations, on the basis of its semantic meaning and its expectable behaviour, rather than standardize everything on the basis of general principles like 'no method modifies the object on which the method is called'.

P.S. If you have time, take also a look to the message I posted to the forum in date Jan 16 "Method return values in jQuery 1.1", for further observations on the subject

comment:4 Changed 13 years ago by sa.cesare@…

comment:5 Changed 13 years ago by john

Milestone: 1.1
Priority: criticalminor
Resolution: wontfix
Status: reopenedclosed
Type: bugenhancement
Version: 1.1

What you're looking for is an equivalent to .push() - .add() is not .push(). We've actively removed all destructive operations from jQuery and it would be counter-intuitive to reintroduce some at the point. For the time being, .add() should remain as it is, with some consideration given to implementing a traditional-style .push(), .slice(), etc.

You can achieve what you're looking for with the following code:

var jq = $('#someDiv');

for (var i = 0; i < someArray.length; i++) {
        if (anything) {
                jq = jq.add(someElement);
        }
}

Or with the following extra method:

jQuery.fn.push = function( elem ) {
    [].push.apply( this, elem.constructor == Array ? elem : [ elem ] );
    return this;
};

comment:6 Changed 9 years ago by rasmus@…

What about performance?

When you need to collect a large number of elements in a selector, it's hardly efficient to keep constructing and throwing away the previous object...

Note: See TracTickets for help on using tickets.