jQuery select data attributes with common keyword
Asked Answered
F

5

7

I have two elements with the following setup:

<span data-placeholder-class="test-class"></span>
<span data-placeholder-template="/some/template.hbs"></span>

I'm using underscore to loop over any elements containing either of these attributes and then performing relevant actions if they do.

Currently this is done like so

_.each($('[data-placeholder-class], [data-placeholder-template]'), function cb(element) {
  // code goes here
})

Rather than have to define each data attribute to loop over I wondered if there was a way I could select all attributes that contain a common keyword, in this case placeholder. e.g.

_.each($('[data-placeholder-*]'), function cb(element) {
  // code goes here
})

Anyone know if this is possible at all?

Floaty answered 24/10, 2016 at 10:10 Comment(6)
Possible duplicate of jQuery - How to select value by attribute name starts withTutt
Does that question have what you're looking for?Tutt
Not quite as they all require a common starting selector e.g. ".slide". Ideally I want to use the data attribute as the only selector so I don't have to add a custom class to any element that has these attributes and I can select by attributes insteadFloaty
Possible duplicate of Find HTML based on partial attributeDexamyl
Right, but check out the info under the "EDIT" section of the selected answer. Above the "EDIT" is an answer specific to his question, but below it is a generic answer.Tutt
@Floaty - Roberrrt's question find is actually better, since you're asking for keyword rather than startswith.Tutt
G
3

You could consider using a separate function which creates your selector, so you won't have to type the selector in full (but you'll have to write the function of course).

e.q.:

function getSelector() {
    return Array.prototype.map.call(arguments, function(key) {
        return '[data-placeholder-' + key + ']';
    }).join(',');
}

This will return your desired selector, and works with 1...N arguments.

getSelector('class', 'template')
// returns "[data-placeholder-template],[data-placeholder-class]"

_.each($(getSelector('class', 'template')), function cb(element) {
    // code goes here
});
Grantham answered 24/10, 2016 at 10:45 Comment(0)
P
1

You can iterate the attributes of a collection of elements, push the element to an array if the element .attributes.name matches a provided string variable

var spans = document.querySelectorAll("span");

function filterAttrs(elems, attr, matches = []) {
  for (var elem of elems) {
    for (var attrs of elem.attributes) {
      // alternatively use `.indexOf()` or `RegExp()`
      // to match parts of string of `.name` or `.value`
      // of `.attributes` `NamedNodeMap`
      if (attrs.name.slice(0, attr.length) === attr) {
        matches.push({
          "element": elem,
          "attr": {
            "name": attrs.name,
            "value": attrs.value
          }
        })
      }
    }
  }
  return matches
}

var matches = filterAttrs(spans, "data-placeholder");

console.log(matches);

matches.forEach(function(match) {
  match.element.textContent = "matches:" + JSON.stringify(match.attr);
  match.element.style.color = "green";
});
<span data-placeholder-class="test-class"></span>
<span data-placeholder-template="/some/template.hbs"></span>
<span data-not-placeholder-template="/some/template.hbs">
data-not-placeholder-template
</span>
<span data-not-placeholder-template="/some/template.hbs">
data-not-placeholder-template
</span>
Pimiento answered 24/10, 2016 at 10:44 Comment(0)
M
1

I know this is a jquery question, but there is a vanilla way of doing it, thanks to XPath queries :

The starts-with() XPath function will do exactly that.

So the query //*[@*[starts-with(name(), 'data-placeholder')]] will give you what you are after.

unwrapped :

 '//' + // from root to anywhere in the tree
  '*' + // any kind of node
   '[@*' + // with any attribute
      '[starts-with(name(), "data-placeholder")]' + // which starts with "data-"
           ']'

function getElementsByStartOfAttribute(start_of_attr) {
  var query = document.evaluate("//*[@*[starts-with(name(), '" + start_of_attr + "')]]",
    document, null, XPathResult.ANY_TYPE, null);
  var elements = [];
  var el;
  while (el = query.iterateNext()) {
    elements.push(el);
  }
  return elements;
}

var placehodlers = getElementsByStartOfAttribute('data-placeholder');
console.log(placehodlers);
$(placehodlers).css('background', 'green');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span data-placeholder-class="test-class">should find me</span>
<span data-placeholder-template="/some/template.hbs">me too</span>
<span data-not-placeholder-template="/some/template.hbs">
data-not-placeholder-template
</span>
<span data-not-placeholder-template="/some/template.hbs">
data-not-placeholder-template
</span>
Mismate answered 11/4, 2017 at 4:23 Comment(0)
H
0
   var eles = $('span').filter(function() {
   for (var attrName in $(this).data()) {
     if (attrName.indexOf('placeholder') == 0) {
       return true;
     }
   }

   return false;
 });

 console.log(eles);

I hope this will help you :)

Haberman answered 24/10, 2016 at 10:44 Comment(0)
I
0

SAMPLE HTML:

<span data-placeholder-class="test-class">test</span>
<span data-placeholder-template="/some/template.hbs">hahaha</span>
<span>hahahahaha</span>
<span data-test="/some/template.hbs">hahahahaha</span>

JS:

$('span').filter(function(ndx, item){
    var data = Object.keys($(item).data())[0]; // gets data name
    if (data === undefined) {
        return;
    }
    // checks if data starts with placeholder
    if (~(data.indexOf('placeholder'))) {
        // do anything to that item here
        return item;
    }
}).css('color', 'green');

Fiddle: here

Hope this helps! :)

Inextricable answered 25/10, 2016 at 8:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.