The importance of timing when working with the DOM
By Flavio Copes
Understand why storing a DOM input value in a variable does not update when the field changes, and how to read the value at submit time instead.
When you read a DOM element’s value and store it in a variable, that variable is a snapshot. It does NOT update when the user later changes the element. To always get the current value, read it at the moment you need it, for example inside the submit event handler.
While working with the students in my bootcamp I helped a few of them navigate this exact problem: timing.
Suppose you have an input field in a form <input id="temperature">, and you get its value in this way:
const temperature = document.querySelector('input#temperature').value
The temperature variable gets the value of the state of the input field at the moment the browser executes this statement, and then the value stays the same forever.
Why does the variable not update?
value is a string, and strings in JavaScript are primitives. When you assign a primitive to a variable, you copy it.
The variable and the input field are now disconnected. The user can type all they want, your copy never changes.
If the script runs when the page loads, the field is probably empty. So temperature is an empty string, and it stays empty.
This is why you can’t do like this:
const temperature = document.querySelector('input#temperature').value
document.querySelector('form')
.addEventListener('submit', event => {
//send the temperature value to your server
})
Read the value when you need it
The fix is to move the read inside the event handler. The handler runs when the user submits, so the value is fresh:
document.querySelector('form')
.addEventListener('submit', event => {
const temperature = document.querySelector('input#temperature').value
//send the temperature value to your server
})
Alternatively you can store the input field reference in a variable, and use that to access its value at submit:
const temperatureElement = document.querySelector('input#temperature')
document.querySelector('form')
.addEventListener('submit', event => {
const temperature = temperatureElement.value
//send the temperature value to your server
})
This works because the variable holds the element object, not a copy of its value. Objects are referenced, not copied. Asking for .value at submit time gives you the current state.
Another timing pitfall
There’s a related mistake: running the script before the element exists.
If your <script> tag sits in the <head> and runs before the form is parsed, document.querySelector('form') returns null, and calling addEventListener on it throws an error.
The fix is to load the script with the defer attribute, or put the script tag at the end of the body. Either way, the DOM is ready when your code runs.
Related posts about js: