Undefined variable inside addEventListener

Why does a EventListener works if you create the function directly but not in a outside function?

I get undefined.

{
const controls = document.querySelector('.controls');
const inputs = controls.querySelectorAll('input');

	inputs.forEach(function(input) {
		input.addEventListener('change', handleUpdate);

		function handleUpdate() {
			const suffix = this.dataset.suffix || '';
			const bla = document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
			console.log(bla);
		}

	});
}

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Scoped CSS Variables and JS</title>
</head>
<body>
  <h2>Update CSS Variables with <span class='hl'>JS</span></h2>

  <div class="controls">
    <label for="spacing">Spacing:</label>
    <input id="spacing" type="range" name="spacing" min="10" max="200" value="10" data-suffix="px">

    <label for="blur">Blur:</label>
    <input id="blur" type="range" name="blur" min="0" max="25" value="10" data-suffix="px">

    <label for="base">Base Color</label>
    <input id="base" type="color" name="base" value="#ffc600">
  </div>

  <img src="https://source.unsplash.com/7bwQXzbF6KE/800x500">

  <style>
    :root {
      --base: #ffc600;
      --spacing: 10px;
      --blur: 10px;
    }

    img {
      padding: var(--spacing);
      background: var(--base);
      filter: blur(var(--blur));
    }

    .hl {
      color: var(--base);
    }

    /*
      misc styles, nothing to do with CSS variables
    */

    body {
      text-align: center;
      background: #193549;
      color: white;
      font-family: 'helvetica neue', sans-serif;
      font-weight: 100;
      font-size: 50px;
    }

    .controls {
      margin-bottom: 50px;
    }

    input {
      width:100px;
    }
  </style>

<script src="js/variables.js"></script>

</body>
</html>

What do you get if you console.log('inputs'); out as your 3rd/4th line?

What i am actually trying to do is set the VALUE directly on change instead of outside the INPUT fields… now its adding it to the DOM HTML element.

querySelectorAll doesn’t give an array, but instead and array-like object called a NodeList.
Your code should work better when you convert it to an array instead.

Also, try to keep functions outside of loop areas. The code might still work, but it makes for better organisation.

function handleUpdate() {
    const suffix = this.dataset.suffix || '';
    const bla = document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
    console.log(bla);
}

Array.from(inputs).forEach(function(input) {
    input.addEventListener('change', handleUpdate);
    ...
});

None of that though deals with why you get undefined. You are getting undefined, because setProperty is designed to return undefined every single time.

What is this supposed to be in the function? Shouldnt you pass the event as param to the function and ask for event.target.dataset and event.target.name instead? Maybe the scope of this is different in your “outside function”. I always use the event param.

about the nodelist iteration:
Although NodeList is not an Array, it is possible to iterate on it using forEach(). Several older browsers have not implemented this method yet.

You can use for…of to loop through a nodelist or forEach. Also you shouldn’t redeclare the function for each iteration.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.