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?

6
  • 1
    Possible duplicate of jQuery - How to select value by attribute name starts with Commented Oct 24, 2016 at 10:13
  • Does that question have what you're looking for? Commented Oct 24, 2016 at 10:14
  • 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 instead Commented Oct 24, 2016 at 10:18
  • 2
    Possible duplicate of Find HTML based on partial attribute Commented Oct 24, 2016 at 10:21
  • 1
    @woolm110 - Roberrrt's question find is actually better, since you're asking for keyword rather than startswith. Commented Oct 24, 2016 at 10:22

5 Answers 5

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
});
Sign up to request clarification or add additional context in comments.

Comments

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>

Comments

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>

Comments

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

Comments

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

Comments

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.