Joshua Burns
Joshua Burns

Reputation: 8572

Grab values of an attribute from all elements in jQuery

Suppose we have the following HTML:

<entries>
  <entry id="1" />
  <entry id="2" />
  <entry id="3" />
  <entry id="4" />
</entries>

Does jQuery have a built-in mechanism for retrieving all values of a specific attribute? And if not, then what is the most efficient way to retrieve them?

Eg, something similar to: $('entry').attrs('id'), returning a list of values across all elements which returns something similar to ["1", "2", "3", "4"]?

jQuery documentation under General Attributes (which is where attr is found,) doesn't give any hint to such a thing existing, and I've found nothing on StackOverflow or any other support forum asking this question.

Upvotes: 6

Views: 446

Answers (4)

ohmu
ohmu

Reputation: 19762

There is not a direct function to do that. However, it can be easily accomplished using .map(). E.g.,

let ids = $('entry').map(function() {
    return this.getAttribute('id');
}).get();

let ids = $('entry').map(function() {
    return this.getAttribute('id');
}).get();

console.log(ids);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<entries>
  <entry id="1" />
  <entry id="2" />
  <entry id="3" />
  <entry id="4" />
</entries>

Upvotes: 2

Danziger
Danziger

Reputation: 21161

You can extend jQuery using jQuery.fn.extend() and add a custom method that iterates over all matching elements, extracting a single or multiple attributes from all of them and pushes/merges them into the returned array/object, respectively.

As the implementation is vanilla JS, this will be faster than working with jQuery objects and functions in all intermediate steps, but might need some tuning depending on which browsers you need to support:

jQuery.fn.extend({
  attrs: function(attributeName) {
    if (attributeName) {
        return this.toArray().map((el) => el.getAttribute(attributeName));
    }
    
    return this.toArray().reduce((merged, el) => {
      const { attributes } = el;
      const totalAttributes = attributes.length;

      for (let i = 0; i < totalAttributes; ++i) {  
        const attribute = attributes[i].nodeName;

        if (merged[attribute]) {
          merged[attribute].push(el.getAttribute(attribute));
        } else {
          merged[attribute] = [el.getAttribute(attribute)];
        }
      }

      return merged;
    }, {});
  },
});

console.log($('entry').attrs());
console.log($('entry').attrs('id'));
console.log($('entry').attrs('class'));
.as-console-wrapper {
  max-height: 100% !important;
}
<entries>
  <entry id="1" class="foo" />
  <entry id="2" class="bar" />
  <entry id="3" class="baz" />
  <entry id="4" class="qux" />
</entries>

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

Upvotes: 0

terrymorse
terrymorse

Reputation: 7086

Here's one way that uses the JavaScript Array .map() function:

let ids = jQuery.makeArray($('entry')).map(entry => entry.id);

console.log('ids:', ids);
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<entries>
  <entry id="1" />
  <entry id="2" />
  <entry id="3" />
  <entry id="4" />
</entries>

Upvotes: 1

Xth
Xth

Reputation: 820

You can use something like that: https://jsfiddle.net/g903dyp6/

<entries>
  <entry id="1" />
  <entry id="2" />
  <entry id="3" />
  <entry id="4" />
</entries>

let arr = $.map($('entry'), function(el) {
     return $(el).attr('id');
});

Upvotes: 2

Related Questions