woolm110
woolm110

Reputation: 1204

jQuery select data attributes with common keyword

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?

Upvotes: 7

Views: 1011

Answers (5)

Kaiido
Kaiido

Reputation: 136568

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>

Upvotes: 1

four
four

Reputation: 564

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! :)

Upvotes: 0

daanvanham
daanvanham

Reputation: 249

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
});

Upvotes: 3

guest271314
guest271314

Reputation: 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>

Upvotes: 1

Rupesh babu Shrestha
Rupesh babu Shrestha

Reputation: 222

   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 :)

Upvotes: 0

Related Questions