Search code examples
javascriptdom-eventsaddeventlistenernodelist

Linking Event Handlers in forEach Loop Javascript NodeList


I'm trying to link the event of two input types in a NodeList. I'm able to link a single pair of inputs but once I add more pairs, I'm unable to link them. What am I doing wrong?

var range = document.querySelectorAll(".inputRange");
var field = document.querySelectorAll(".inputNumber");
// console.log(range);
// console.log(field);

range.forEach(input => {
  input.addEventListener("input", e => {
    // console.log("RANGE EVENT: " +e.type)
    field.value = e.target.value;
  });
});
field.forEach(input => {
  input.addEventListener("input", e => {
    range.value = e.target.value;
  });
});
<div class="card grd">
  <h4 class="r1">Recipe</h4>
  <p>Low</p>
  <h2 class="r2"><input class="inputNumber" id="num1" min="0" max="100" type="number" value="0.75" step=".01" maxlength="8" /></h2>
  <div class="sldcon">
    <input class="inputRange" id="range" type="range" min="0" max="100" value="0.75" step=".01" />
  </div>
  <p>Mid</p>
  <h2 class="r2"><input class="inputNumber" id="num1" min="0" max="100" type="number" value="35" step=".01" maxlength="8" /></h2>
  <div class="sldcon">
    <input class="inputRange" id="range" type="range" min="0" max="100" value="35" step=".01" />
  </div>
  <p>High</p>
  <h2 class="r2"><input class="inputNumber" id="num1" min="0" max="1000" type="number" value="40" step=".01" maxlength="8" /></h2>
  <div class="sldcon">
    <input class="inputRange" id="range" type="range" min="0" max="1000" value="40" step=".01" />
  </div>
</div>


Solution

  • Iterate over only one of the collections, and inside the loop, get a reference to the linked input by navigating the nearby DOM, then add listeners to both:

    document.querySelectorAll(".inputNumber").forEach((field) => {
      const range = field.parentElement.nextElementSibling.children[0];
      range.oninput = () => field.value = range.value;
      field.oninput = () => range.value = field.value;
    });
    <div class="card grd">
      <h4 class="r1">Recipe</h4>
      <p>Low</p>
      <h2 class="r2"><input class="inputNumber" id="num1" min="0" max="100" type="number" value="0.75" step=".01" maxlength="8" /></h2>
      <div class="sldcon">
        <input class="inputRange" id="range" type="range" min="0" max="100" value="0.75" step=".01" />
      </div>
      <p>Mid</p>
      <h2 class="r2"><input class="inputNumber" id="num1" min="0" max="100" type="number" value="35" step=".01" maxlength="8" /></h2>
      <div class="sldcon">
        <input class="inputRange" id="range" type="range" min="0" max="100" value="35" step=".01" />
      </div>
      <p>High</p>
      <h2 class="r2"><input class="inputNumber" id="num1" min="0" max="1000" type="number" value="40" step=".01" maxlength="8" /></h2>
      <div class="sldcon">
        <input class="inputRange" id="range" type="range" min="0" max="1000" value="40" step=".01" />
      </div>
    </div>

    Or you could reference the same index on the other collection:

    const ranges = document.querySelectorAll(".inputRange");
    document.querySelectorAll(".inputNumber").forEach((field, i) => {
      const range = ranges[i];
      range.oninput = () => field.value = range.value;
      field.oninput = () => range.value = field.value;
    });
    <div class="card grd">
      <h4 class="r1">Recipe</h4>
      <p>Low</p>
      <h2 class="r2"><input class="inputNumber" id="num1" min="0" max="100" type="number" value="0.75" step=".01" maxlength="8" /></h2>
      <div class="sldcon">
        <input class="inputRange" id="range" type="range" min="0" max="100" value="0.75" step=".01" />
      </div>
      <p>Mid</p>
      <h2 class="r2"><input class="inputNumber" id="num1" min="0" max="100" type="number" value="35" step=".01" maxlength="8" /></h2>
      <div class="sldcon">
        <input class="inputRange" id="range" type="range" min="0" max="100" value="35" step=".01" />
      </div>
      <p>High</p>
      <h2 class="r2"><input class="inputNumber" id="num1" min="0" max="1000" type="number" value="40" step=".01" maxlength="8" /></h2>
      <div class="sldcon">
        <input class="inputRange" id="range" type="range" min="0" max="1000" value="40" step=".01" />
      </div>
    </div>