Bug Tracker

Ticket #8897 (closed feature: wontfix)

Opened 4 years ago

Last modified 2 years ago

append() should work with an array of jQuery objects

Reported by: humaninternals <nadav+jquery@…> Owned by:
Priority: low Milestone: 1.next
Component: core Version: 1.5.2
Keywords: Cc:
Blocking: Blocked by:

Description

This works as expected (array of DOM elements):

$(document.createElement('form'))
        .append([document.createElement('input')]);

But passing an array of jQuery objects:

$(document.createElement('form'))
        .append([$(document.createElement('input'))]);

Fails with Uncaught Error: NOT_FOUND_ERR: DOM Exception on Chrome and Node cannot be inserted at the specified point in the hierarchy" code: "3 on Firefox. It can be seen  here.

I assume this isn't intentional and that it should work, shouldn't it?

Change History

comment:1 Changed 4 years ago by timmywil

  • Priority changed from undecided to low
  • Resolution set to invalid
  • Status changed from new to closed
  • Component changed from unfiled to core

jQuery understands passing an array of elements as it can be easily converted to a jQuery object. Passing an array of jQuery objects is not supported.

comment:2 Changed 4 years ago by humaninternals <nadav+jquery@…>

Well, I am aware that its not supported, but why wouldn't it be? Is there any special reason you wouldn't want to support that? It should be easy enough to add support for that.

Its really annoying in cases you dynamically create multiple children, such as $('<ul>').append($.map(["foo", "bar"], function(val){ return $("<li>").text(val); }). Adding support for that can really benefit for those cases.

I do realize I can manually call .get(0) to transform those jQuery object to DOM elements, but... its much cleaner if it'll be done by jQuery itself instead of by the developer.

comment:3 Changed 4 years ago by timmywil

  • Status changed from closed to reopened
  • Type changed from bug to feature
  • Resolution invalid deleted

Fair enough. This is more of a feature request then. I was going to say we have discussed this in the past and decided it would be too costly to support. However, I think I have an idea on how to support it, but I want to do more performance testing first.

comment:4 Changed 4 years ago by timmywil

  • Status changed from reopened to closed
  • Resolution set to wontfix

My idea didn't pan out. I think this would be too costly to support as was previously indicated by ajpiano.

comment:5 Changed 4 years ago by humaninternals <nadav+jquery@…>

Oh, well.. if anyone stumbles here expecting this to work, you can (function($){var jq_append = $.fn.append; $.fn.append = function(arr) { return $.isArray(arr) ? jq_append.call(this, $.map(arr, function(el){ return el instanceof $ ? el.get() : el; })) : jq_append.apply(this, arguments); }})(jQuery); to add support for that. It'll also work with an array that contains both DOM elements and jQuery objects - but when the first argument is an array it'll ignore the other arguments. Do note that duck punching it like that is somewhat slower and more resource intensive.

comment:6 Changed 3 years ago by miasnikov@…

Would be really helpful to fix it, otherwise we have to spread .get(0) across code to make it working. Very annoying.

comment:7 Changed 3 years ago by anonymous

this is surely not a feature request, if you pass an array you simply expect it to appended just like any other jquery method, it's a bit confusing that it's not compatible with it's own object model.

comment:8 follow-up: ↓ 10 Changed 3 years ago by ajpiano

What about a 2 level deep array of arrays that contains jQuery objects? An object where some of the members are jQuery objects and some are not? There are essentially infinite permutations of input that .append() (etc) could accept, just because somewhere nested deep inside somewhere, is a bunch of DOM elements. We can't reasonably support all these possible variations, and not doing so doesn't mean that jQuery "isn't compatible with it's own object model," it means that there's a difference between accepting a certain data type as input and accepting *any* data type as input just because somewhere inside that structure exists the first, acceptable data type.

comment:9 Changed 3 years ago by narcvs@…

Another monkey-patch to enable this:  https://gist.github.com/2951521

comment:10 in reply to: ↑ 8 Changed 2 years ago by Jeremy

Replying to ajpiano:

We can't reasonably support all these possible variations

Would you mind taking just a moment to expand on that? It seems to me that a fairly simple recursive operation, with a function like the following, could solve every possible permutation that append might be expected to accept (including every one you mentioned, which means accepting arrays with a mix of other arrays/jQuery objects/raw elements/strings):

function newAppend(stuff) {
  if(isRawElement(stuff) || typeof stuff == 'string') {
    // Cover strings and raw elements
    this.oldAppend(stuff);
  } else  if (isJQueryObject(stuff)) {
    // Cover jQuery objects
    stuff.appendTo(this);
  } else if (isArray(stuff)) {
    // Cover arrays of *anything*
    var thiz = this; // Could use $.proxy instead
    $.each(stuff, function(i, subStuff) {
      newAppend.call(thiz, subStuff);
    })
  } else {
    throw "What garbage have you given me you crazy developer!?!?";
  }

comment:11 Changed 2 years ago by Mustafa

This seems like an intuitive way of using the append() method. A developer should not expect nested arrays to be recursively cycled through for this method (although that would be nice and pretty simple) but expecting it to at least understand jquery objects is not asking too much.

comment:12 Changed 2 years ago by dmethvin

If you like this idea, please use one of the suggested patches above or make a plugin.

Note: See TracTickets for help on using tickets.