0

I often need to convert the result of a selector to an array of JQuery objects so that I can for..of on them, I end up doing a lot of:

const arr = $.makeArray($(selector)).map(el => $(el));

(I usually have a function doing this internally)

I then do things like:

for (let jel of arr) jel.toggle(false);

Does JQuery have a better/builtin way to create such arr ?

9
  • get. There's bound to be a previous question on this, I'll see if I can find one. Commented Sep 9, 2022 at 21:53
  • You can use Array.from(collection) or [...collection] as the generic way to convert an array-like object to a real array. But why do you need to use for-of when jQuery has a built-in $(selector).each(...)? Commented Sep 9, 2022 at 21:55
  • the point is to convert back to a result array where each item is not a dom object but a JQuery object Commented Sep 9, 2022 at 21:57
  • @kofifus - Sorry, misunderstood that. I'm curious what the use case is...? Vs. just using $() on what you get in the for-of? Commented Sep 9, 2022 at 22:00
  • 2
    hmm... I'm confused. Why aren't you just using $(selector).toggle(false)? feel like i'm missing something, since noone's mentioned this yet. There's rarely ever a need to actually have an array of individual jquery collections. jquery methods already implicitly work on each element individually. Commented Sep 9, 2022 at 22:05

1 Answer 1

3

As Kevin points out, in that specific case, there's no reason for the loop. toggle operates on the entire collection, so simply $("selector").toggle(false) (or $("selector").hide();). This is one of the great things about jQuery, it's set-based (for setters and actions; not for getters).

But if the goal is to get an array of individual jQuery wrappers around every element in a jQuery object, your version seems fine, but it can be slightly simpler:

const arr = Array.from($(selector), el => $(el));

That uses the mapping callback on Array.from, avoiding an unnecessary intermediate array:

const wrappers = Array.from($(".a"), (el) => $(el));
for (const wrapper of wrappers) {
    console.log(wrapper.text());
}
<div class="a">1</div>
<div class="a">2</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

If the goal is just to get an iterable (rather than an array) that can be used with for-of and anything else that understands iterables, wrapping each individual element in a jQuery wrapper, you could add a function (plugin) to do that using a generator function:

// The plugin
(($) => {
    jQuery.fn.wrapped = function*() {
        for (let n = 0; n < this.length; ++n) {
            yield $(this[n]);
        }
    };
})(jQuery);

// Using it
for (const wrapper of $(".a").wrapped()) {
    console.log(wrapper.text());
}
<div class="a">1</div>
<div class="a">2</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Or as a static method inspired by your comment below:

// The plugin
(($) => {
    $.iterable = function*(...args) {
        const wrapper = $(...args);
        for (let n = 0; n < wrapper.length; ++n) {
            yield $(wrapper[n]);
        }
    };
})(jQuery);

// Using it
for (const wrapper of $.iterable(".a")) {
    console.log(wrapper.text());
}
<div class="a">1</div>
<div class="a">2</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Sign up to request clarification or add additional context in comments.

2 Comments

oh cool I didn't know Array.from can do this ! glad I asked
instead of you plugin I added: JQuery.from = function (selector) { return Array.from($(selector), el => $(el)); } I can then for .. of $.from('.class')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.