How can I connect a value of an range input with an output tag?

Viewed 90

I'm trying to connect my input range value change with an output. I mean when I move the range input the current value should be shown in the site. I tried it via using form with "oninput" and <output>. It works but I would like to know how to use it with JS. When I use forEach, the one input value which I change applies on other inputs. How to change only the corresponding output?

Below the image

)

My code:

window.addEventListener("DOMContentLoaded", () => {
  const filters = document.querySelectorAll(".filters input"),
    output = document.querySelectorAll("output");

  function handleUpdate() {
    const suffix = this.dataset.sizing || "";
    document.documentElement.style.setProperty(
      `--${this.name}`,
      this.value + suffix
    );
    output.forEach((out) => {
      out.value = this.value;
    });
  }

  filters.forEach((input) => input.addEventListener("change", handleUpdate));
  filters.forEach((input) => input.addEventListener("mousemove", handleUpdate));
});
label {
  display: block;
}
<div class="filters">
  <label>
    Blur:
    <input
      name="blur"
      data-sizing="px"
      type="range"
      min="0"
      max="10"
      value="0"
      id="blur"
    />
    <output name="result" for="blur">0</output>
  </label>

  <label>
    Invert:
    <input
      name="invert"
      data-sizing="%"
      type="range"
      min="0"
      max="100"
      value="0"
      id="invert"
    />
    <output name="result">0</output>
  </label>

  <label>
    Sepia:
    <input
      name="sepia"
      data-sizing="%"
      type="range"
      min="0"
      max="100"
      value="0"
      id="sepia"
    />
    <output name="result">0</output>
  </label>

  <label>
    Saturate:
    <input
      name="saturate"
      data-sizing="%"
      type="range"
      min="0"
      max="200"
      value="100"
      id="saturate"
    />
    <output name="result">100</output>
  </label>

  <label>
    Hue rotate:
    <input
      name="hue"
      data-sizing="deg"
      type="range"
      min="0"
      max="360"
      value="0"
      id="hue"
    />
    <output name="result">0</output>
  </label>
</div>

2 Answers

You are looping with every call of handleUpdate() through all output elements with output.forEach(.... To select only the corresponding output element you could use nextElementSibling (if the next sibling is the output):

this.nextElementSibling.value = this.value;

Working example:

window.addEventListener("DOMContentLoaded", () => {
  const filters = document.querySelectorAll(".filters input"),
    output = document.querySelectorAll("output");

  function handleUpdate() {
    const suffix = this.dataset.sizing || "";
    document.documentElement.style.setProperty(
      `--${this.name}`,
      this.value + suffix
    );
    this.nextElementSibling.value = this.value;
  }

  filters.forEach((input) => input.addEventListener("change", handleUpdate));
  filters.forEach((input) => input.addEventListener("mousemove", handleUpdate));
});
label {
  display: block;
}
<div class="filters">
  <label>
    Blur:
    <input
      name="blur"
      data-sizing="px"
      type="range"
      min="0"
      max="10"
      value="0"
      id="blur"
    />
    <output name="result" for="blur">0</output>
  </label>

  <label>
    Invert:
    <input
      name="invert"
      data-sizing="%"
      type="range"
      min="0"
      max="100"
      value="0"
      id="invert"
    />
    <output name="result">0</output>
  </label>

  <label>
    Sepia:
    <input
      name="sepia"
      data-sizing="%"
      type="range"
      min="0"
      max="100"
      value="0"
      id="sepia"
    />
    <output name="result">0</output>
  </label>

  <label>
    Saturate:
    <input
      name="saturate"
      data-sizing="%"
      type="range"
      min="0"
      max="200"
      value="100"
      id="saturate"
    />
    <output name="result">100</output>
  </label>

  <label>
    Hue rotate:
    <input
      name="hue"
      data-sizing="deg"
      type="range"
      min="0"
      max="360"
      value="0"
      id="hue"
    />
    <output name="result">0</output>
  </label>
</div>


Alternatively you could select the parent with parentElementand then the output, for example if the output isn't a direct sibling of the input:

this.parentElement.querySelector('output').value = this.value;

Working example:

window.addEventListener("DOMContentLoaded", () => {
  const filters = document.querySelectorAll(".filters input"),
    output = document.querySelectorAll("output");

  function handleUpdate() {
    const suffix = this.dataset.sizing || "";
    document.documentElement.style.setProperty(
      `--${this.name}`,
      this.value + suffix
    );
    this.parentElement.querySelector('output').value = this.value;
  }

  filters.forEach((input) => input.addEventListener("change", handleUpdate));
  filters.forEach((input) => input.addEventListener("mousemove", handleUpdate));
});
label {
  display: block;
}
<div class="filters">
  <label>
    Blur:
    <input
      name="blur"
      data-sizing="px"
      type="range"
      min="0"
      max="10"
      value="0"
      id="blur"
    />
    <output name="result" for="blur">0</output>
  </label>

  <label>
    Invert:
    <input
      name="invert"
      data-sizing="%"
      type="range"
      min="0"
      max="100"
      value="0"
      id="invert"
    />
    <output name="result">0</output>
  </label>

  <label>
    Sepia:
    <input
      name="sepia"
      data-sizing="%"
      type="range"
      min="0"
      max="100"
      value="0"
      id="sepia"
    />
    <output name="result">0</output>
  </label>

  <label>
    Saturate:
    <input
      name="saturate"
      data-sizing="%"
      type="range"
      min="0"
      max="200"
      value="100"
      id="saturate"
    />
    <output name="result">100</output>
  </label>

  <label>
    Hue rotate:
    <input
      name="hue"
      data-sizing="deg"
      type="range"
      min="0"
      max="360"
      value="0"
      id="hue"
    />
    <output name="result">0</output>
  </label>
</div>

Made for me a quick example to understand what you want to achieve. Just add a listener for each range input and put in the output input value of range input after change is made.

HTML

<input type="range" min="0" max="3" id="range">
<input type="text" disabled id="output">

JS

document.querySelector("#range").addEventListener("change", ({target}) => {
   document.querySelector("#output").value = target.value
})

If you have many inputs and you want to add this to corresponding ones... you can rearrange the HTML and use querySelectorAll and loop through this NodeList and you have this solution

HTML

<label><input type="range" min="0" max="3" class="range-input"><input type="text" disabled class="output-input"></label>
<label><input type="range" min="0" max="3" class="range-input"><input type="text" disabled class="output-input"></label>
<label><input type="range" min="0" max="3" class="range-input"><input type="text" disabled class="output-input"></label>

JS

document.querySelectorAll("label").forEach(label => {
   label.querySelector(".range-input").addEventListener("change", ({target}) => {
      label.querySelector(".output-input").value = target.value
   })
})

Working example:

document.querySelectorAll("label").forEach(label => {
  label.querySelector(".range-input").addEventListener("change", ({target}) => {
    label.querySelector(".output-input").value = target.value
  })
})
label {
  display: block;
}
<label>
  <input type="range" min="0" max="3" class="range-input">
  <input type="text" disabled class="output-input">
</label>

<label>
  <input type="range" min="0" max="3" class="range-input">
  <input type="text" disabled class="output-input">
</label>

<label>
  <input type="range" min="0" max="3" class="range-input">
  <input type="text" disabled class="output-input">
</label>

Related