Vanilla Javascript: Find a data attribute of the same name as an element given its id
Asked Answered
D

3

6

Is it possible to find an element that has a data attribute with the same name of an element's id in the DOM? (Is it a bad practice to give a data attribute the same value as an id?)

Example syntax:

HTML:

<li id="tab-1"></li>
<p data-tab="tab-1">Content 1</p>

Would be curious as to how to accomplish this in Vanilla Javascript. Thank you ☺

Edit: I am hoping to make my code so that if I have the ID of the element, I can just look for a data attribute of the same value if I don't have it off the top of my head.

Dalliance answered 11/4, 2017 at 1:37 Comment(4)
querySelectorWinded
"is it bad practice" ... not at all if there is a close relationship between the two. Not entirely clear what you are exactly asking though. What use case are you wanting for "find same as"?Buffington
"Edit: I am hoping to make my code so that if I have the ID of the element, I can just look for a data attribute of the same value if I don't have it off the top of my head." You would need the specific .name of the data-* attribute. css selectors do not provide a means to select elements by value of attribute alone.Spotter
"Is it possible to find an element that has a data attribute with the same name of an element's id" The data-* attribute does not have .name property that is equal to .id of element at Question.Spotter
A
12

Yes, you can do that. Here's how you do it:

var usingId = document.querySelector('#tab-1');
var usingDt = document.querySelector('[data-tab="tab-1"]');
console.log(usingId);
console.log(usingDt);
<li id="tab-1">Tab</li>
<p data-tab="tab-1">P Tab</p>

Is it a bad practice?.Nope

Anon answered 11/4, 2017 at 1:44 Comment(0)
S
1

If you are trying to select an element having an unknown html5 data-* attribute using the .id string property from a different element, you can query all elements in document, check the .name and .value of each elements' .attributes, if .value of attribute is equal to .id of element which provides .id and .name of the .attribute property is not "id", the element is matched using attribute equals selector at .querySelector()

<li id="tab-1"></li>
<p data-tab="tab-1">Content 1</p>
<script>
let id = document.getElementById("tab-1").id;
for (let el of document.querySelectorAll("*")) {
  for (let {name, value} of el.attributes) {  
  if (value === id && name !== "id") {
     document.querySelector(`[${name}="${id}"]`)
     .style.color = "green";
     break;
  }
  }
}
</script>
Spotter answered 11/4, 2017 at 1:51 Comment(6)
let id = document.getElementById("tab-1").id; this made my day. Thanks. (you could also do let id = document.getElementById("tab-1").id.split('').join('').replace(/a/g, 'a');)Ailsa
@Ailsa Or let {id} = document.getElementById("tab-1"). Was only trying to answer Question as interpreted. That is, query document for element using only .id to match value of data-* attribute.Spotter
@Ailsa As interpreted the Question, the .name of the data-* attribute was not provided, onlt the .value being same as .id of a different element. css selectors do not select an element by value of attribute alone. Though it can be done by composing a function to do so.Spotter
Ok, css selectors are not the way then, but still this let id= ... is completely useless and funny. And instead of looping like that over all elements of quesrySelctorAll, you should use a DOMTreeWalker, it's way more efficient, and only elements can have attributes.Ailsa
@Ailsa Enlivening to be aware approach provided you with humor. Have not tried DomTreeWalker; perhaps post an Answer as to your interpreation of Question and decided approach?Spotter
TreeWalker is not the best either for this use case, but you should definitely give it a try. developer.mozilla.org/en-US/docs/Web/API/Document/…Ailsa
A
0

If the requisite is to not know the name of the attribute which value is the string you are looking for, then you can create an XPath query, which will return you all the elements having an attribute with such value :

//*[@*='value']

unwrapped :

'//' + // from root to anywhere in the tree
   '*' + // any kind of node
     '[@*' + // with any attribute
         ' = "value"' // which value is 'value'
                      ']'

var valueToFind = 'find-me';
var query = document.evaluate(`//*[@*='${valueToFind}']`, document, null, XPathResult.ANY_TYPE, null);
var elements = [], el;
while(el = query.iterateNext()){
  // in your case you will filter it to not be the original node 
  // if(el !== original)
  elements.push(el);
  }
console.log(elements);
<div data-id="find-me"></div>
<div data-id="do-not-find-me"></div>
<div class="find-me"></div>
<div class="do-not-find-me"></div>
<div style="find-me"></div>
<div id="find-me"></div>

And if the goal is to get only the elements with data-* attributes with such value, then the query is a bit more long :

//*[@*[starts-with(name(), 'data-')] = '${valueToFind}']

unwrapped :

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

var valueToFind = 'find-me';
var query = document.evaluate(`//*[@*[starts-with(name(), 'data-')] = '${valueToFind}']`, document, null, XPathResult.ANY_TYPE, null);
var elements = [], el;
  
while(el = query.iterateNext()){
  elements.push(el);
  }
console.log(elements);
<div data-id="find-me"></div>
<div data-foo="find-me"></div>
<div data-id="do-not-find-me"></div>
<div class="find-me"></div>
<div class="do-not-find-me"></div>
<div style="find-me"></div>
<div id="find-me"></div>
Ailsa answered 11/4, 2017 at 2:27 Comment(6)
OP is specifically trying to select element having data-* attribute having value equal to a different element .id. Is @* a wildcard? if yes, how to adjust to match only element having data-* attribute?Spotter
@Spotter there is no way I know of to make partially wildcarded values, so you'd have to filter it in the while loop : you just have to check for if([].some.call(el.attributes, a=>{return a.nodeName.indexOf('data-') === 0 && a.nodeValue === "value";})); You will already have filtered a huge part of the document's nodes.Ailsa
Why do you not perform the task at Answer? Granted, Question is not entirely clear as to "Is it possible to find an element that has a data attribute with the same .name of an element's id" as the data-* attribute is "data-tab", not "data-tab-1". Perhaps OP means having the same data-* value as a different elements' .id value?Spotter
@guest271314, added a new snippet with the filtering, I have to admit I'm confused too as to what is the real requirement.Ailsa
See also #35806927, #40216273Spotter
@Spotter actually there is a starts-with XPath function... I didn't know ;-) Answered the second link too, but the first one is a bit unrelated and the dataset method is probably cleaner.Ailsa

© 2022 - 2024 — McMap. All rights reserved.