I have some input elements and I want to create a reset button, so that I can programatically revert their values
to their original state.
Here is my code:
let people = document.getElementsByClassName('person')
function reset() {
for (var key in people) {
let string = people[key].dataset.name
people[key].value = string
}
}
let app = document.getElementById('app')
let button = document.createElement('button')
button.innerHTML = "reset"
button.addEventListener('click', reset)
app.append(button)
<div id="app">
<input class="person" data-name="John" value="John">
<input class="person" data-name="Steve" value="Steve">
<input class="person" data-name="Peter" value="Peter">
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
This actually works as intended, but I get an error saying that the value of 'data-name'
cannot be read, but this cannot be true as the function works as intended.
Does anyone know what is happening here and how I can fix this?
CodePudding user response:
in
iterates over all enumerable properties in not only the object itself, but also in all objects in the internal prototype chain. Log the key, and you'll see:
let people = document.getElementsByClassName('person')
function reset() {
for (var key in people) {
console.log(key);
}
}
reset();
<div id="app">
<input class="person" data-name="John" value="John">
<input class="person" data-name="Steve" value="Steve">
<input class="person" data-name="Peter" value="Peter">
</div>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
The HTMLCollection has more enumerable properties than just 0
, 1
, and 2
, so trying to access the .dataset
on those other properties fails.
Use for..of
instead, to invoke the collection's iterator (which will only iterate over the elements in the collection, as desired).
let people = document.getElementsByClassName('person')
function reset() {
for (const input of people) {
input.value = input.dataset.name;
}
}
let app = document.getElementById('app')
let button = document.createElement('button')
button.innerHTML = "reset"
button.addEventListener('click', reset)
app.append(button)
<div id="app">
<input class="person" data-name="John" value="John">
<input class="person" data-name="Steve" value="Steve">
<input class="person" data-name="Peter" value="Peter">
</div>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
In general, I'd suggest avoiding in
loops usually - often, for..of
or Object.keys
or Object.entries
work better.
CodePudding user response:
This line of code here
for (var key in people)
should be
for (let i = 0; i < people.length; i )
as the for...in... loop will also get the length
property of the people
HTMLCollection. You would then be accessing the value
property of people.length
, which does not exist.
Completed Code:
let people = document.getElementsByClassName('person')
function reset() {
for (let i = 0; i < people.length; i ) {
let string = people[i].dataset.name
people[i].value = string
}
}
let app = document.getElementById('app')
let button = document.createElement('button')
button.innerHTML = "reset"
button.addEventListener('click',reset)
app.append(button)
<div id="app">
<input class="person" data-name="John" value="John">
<input class="person" data-name="Steve" value="Steve">
<input class="person" data-name="Peter" value="Peter">
</div>
<iframe name="sif4" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>