2

I have a few inputs that have a label above them. I want to find the closest label for each of them. The issue is some of the inputs don't have a direct label above them.

Initially I had this:

let el = document.querySelector(`label[for="${this.element.id}"]`)

This worked for all case except some rare cases where I had two inputs in one line, like test and test2. How can I get the test label for the test2 input?

<div>
      <label for="test">Interval</label><br>
      <input min="0.1" id="test" placeholder="Min" step="0.1" type="number">
      <input min="0.1" id="test2" placeholder="Max" step="0.1" type="number">

      <label for="limit">Limit</label><br>
      <input id="limit" step="1" type="number">
</div>
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
HeelMega
  • 458
  • 8
  • 23
  • see this https://stackoverflow.com/questions/9004307/two-input-fields-inside-one-label. you shouldn't use a single label with 2 inputs – Ovidiu Dolha Jun 24 '20 at 14:27
  • I know but the only reason I want to get the closest label is too append an icon to it. So I m not using 1 label for 2 inputs just need it to show a pending call status @OvidiuDolha – HeelMega Jun 24 '20 at 14:29
  • @OvidiuDolha your link is a valid thing, however the situation seems different, as the label is here not wrapped around the inputs. Technically the OP's code is semantically correct, and the label is associated to only one input by its id – Kaddath Jun 24 '20 at 14:30
  • @HeelMega Can we assume the right libel is always situated **before** the input? If so, maybe you should rephrase your title, as in your example case the label you want is not the closest (it's the one under) – Kaddath Jun 24 '20 at 14:34
  • @Kaddath yes, absolutely – HeelMega Jun 24 '20 at 14:34

3 Answers3

4

You can use aria-labelledby attribute for this instead. The aria-labelledby attribute establishes relationships between objects and their label(s), and its value should be one or more element IDs.

Here, we can assume test2 is actually what you have in the code like this.element.id. Using that we can get the aria-labelledby attribute value using getAttribute() method. Then we can simply pass that to document.querySelector to get the closest label w.r.t the input id.

let input = document.querySelector(`#test2`)
let labelId = input.getAttribute('aria-labelledby')

let el1 = document.querySelector(`label[id="${labelId}"]`)
el1.style.color = "green"
<div>
  <label id="interval">Interval</label><br>
  <input min="0.1" id="test" placeholder="Min" step="0.1" type="number" aria-labelledby="interval">
  <input min="0.1" id="test2" placeholder="Max" step="0.1" type="number" aria-labelledby="interval">
</div>
palaѕн
  • 72,112
  • 17
  • 116
  • 136
2

I made a function searchLabel for you!

function searchLabel(inputElem) {
  var elem = inputElem;
  while (true) {
    if (elem.tagName == "LABEL") {
      break;
    }
    if (elem == null) {
      break;
    }
    elem = elem.previousSibling;
  }
  return elem;
}
console.log(searchLabel(document.getElementById("test2")));
<div id="myDiv">
  <label for="test">Interval</label><br>
  <input min="0.1" id="test" placeholder="Min" step="0.1" type="number">
  <input min="0.1" id="test2" placeholder="Max" step="0.1" type="number">

  <label for="limit">Limit</label><br>
  <input id="limit" step="1" type="number">
</div>
Antoni
  • 356
  • 5
  • 17
1

You can find the nearest parent label element in the DOM using a little manual DOM traversal like so:

function nearestParentLabel(inputId) {
  let input = document.getElementById(inputId);
  let label = input.previousSibling;
  while (label != null && label.tagName != "LABEL") {
    label = label.previousSibling;
  }
  return label;
}

console.log(
  nearestParentLabel("test"), // returns "test" label
  nearestParentLabel("test2"), // returns "test" label
  nearestParentLabel("limit"), // returns "limit" label
);
<div>
      <label for="test">Interval</label><br>
      <input min="0.1" id="test" placeholder="Min" step="0.1" type="number">
      <input min="0.1" id="test2" placeholder="Max" step="0.1" type="number">

      <label for="limit">Limit</label><br>
      <input id="limit" step="1" type="number">
</div>
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98