Usuwanie opcji ze znacznika Select w JavaScript Vanilla za pomocą pętli „for .. of”

10

Podczas próby usunięcia opcji z wyboru zawsze pozostaje jedna, dlaczego?

<select id="form-select">   
<option>111</option>
<option>222</option>
<option>333</option>
</select>

Ten JS nie działa:

var t = document.querySelector('#form-select'); 
for(var i of t.options) {
      t.remove(i.index)
    }

To też nie działa:

for(var i of document.querySelector('#form-select').options) {
  i.remove()
}

Wiem, że istnieją inne rozwiązania, aby to osiągnąć, ale chciałbym zrozumieć, dlaczego to nie działa tak, jak powinno

Piotr
źródło

Odpowiedzi:

7

.optionsKolekcja jest (niestety) na żywo , więc iteracji przez elementy kolekcja Live za jeden po drugim i .removeing każdy spowoduje każdej nieparzystej jeden trzymane. (Np, tuż po wyjęciu pierwszego elementu, [0]th element kolekcji natychmiast stać się następny element w kolekcji - co kiedyś [1]staną się [0](a następnie raz przejść do następnego indeksu w [1]The nowa pozycja w pozycji 0 się nie powtórzy)

document.querySelectorAllZamiast tego użyj , który zwraca statyczną kolekcję:

for (const option of document.querySelectorAll('#form-select > option')) {
  option.remove();
}
<select id="form-select">
  <option>111</option>
  <option>222</option>
  <option>333</option>
</select>

Możesz również przenieść się do tablicy (statycznej) przed usunięciem elementów:

for (const option of [...document.querySelector('#form-select').options]) {
  option.remove();
}
<select id="form-select">
  <option>111</option>
  <option>222</option>
  <option>333</option>
</select>

Innym rozwiązaniem, które właśnie się dzieje, do pracy, ponieważ kolekcja jest na żywo (ale prawdopodobnie nie powinny być stosowane, ponieważ nie jest intuicyjny):

const { options } = document.querySelector('#form-select');
while (options.length) {
  options[0].remove();
}
<select id="form-select">
  <option>111</option>
  <option>222</option>
  <option>333</option>
</select>

CertainPerformance
źródło
3

Usuwasz elementy z tablicy podczas iteracji po tablicy. Więc masz:

["one","two","three"]

następnie usuwasz element o indeksie 0, który jest „jeden”, pozostawiając ci:

["two","three"]

następnie usuwasz element o indeksie 1, czyli „trzy”, pozostawiając ci:

["two"]

pod indeksem 2 nie ma pozycji, więc pętla się zatrzymuje.

Zamiast tego iteruj po tablicy w odwrotnej kolejności :

const t = document.querySelector("#form-select")

for (let i = t.options.length-1; i >= 0; i--) {
  t.removeChild(t.options[i])
}
<select id="form-select">
  <option>111</option>
  <option>222</option>
  <option>333</option>
</select>

dowiązanie symboliczne
źródło
.optionsTo nie tablica, która jest źródłem problemu - to raczej HTMLCollection, który znajduje się pod napięciem. Gdyby to była tablica, byłaby statyczna i nie byłoby żadnych problemów.
CertainPerformance
1
@CertainPerformance usuwanie elementów z tablicy jak iterację to robi przyczyną problemu Mam przedstawionego.
dowiązanie symboliczne
1
@CertainPerformance HTMLOptionsCollectionObiekt działa w tym kontekście jak tablica.
dowiązanie symboliczne
2

Widzę, że twoim głównym celem jest zrozumienie procesu, który to powoduje, więc powinno to zilustrować problem:

var arr = ["one", "two", "three", "four", "five", "six"];

for(var i = 0; i < arr.length; i++){
	console.log("i is " + i + ", so we are removing \"" + arr[i] + "\" from " + JSON.stringify(arr) + ".");
	arr.splice(i, 1);
	console.log("After that removal, the array is " + JSON.stringify(arr) + ". We'll now iterate i to " + (i + 1) + " and continue the loop.");
}
console.log("i is too high to grab a value from the array, so we're finished. We're left with " + JSON.stringify(arr) + ".");

Ta pętla przechodzi dokładnie ten sam rodzaj procesu, co twoja pętla „for .. of”, aby dać ci dodatkowe efekty w końcowym wyniku. Problem polega na tym, że niszczy swoje własne indeksy podczas ich iteracji, zmieniając w ten sposób wartość, do której itak naprawdę się odnosi. Kiedy mam do czynienia z tym problemem, lubię zapętlać tablicę do tyłu, aby moje własne zniszczenie nie miało na mnie wpływu, tak:

var arr = ["one", "two", "three", "four", "five", "six"];

for(var i = arr.length - 1; i >= 0; i--){
	console.log("i is " + i + ", so we are removing \"" + arr[i] + "\" from " + JSON.stringify(arr) + ".");
	arr.splice(i, 1);
	console.log("After that removal, the array is " + JSON.stringify(arr) + ". We'll now iterate i to " + (i - 1) + " and continue the loop.");
}
console.log("i is too low to grab a value from the array, so we're finished. We're left with " + JSON.stringify(arr) + ".");

Mam nadzieję, że to pomoże ci dokładnie zrozumieć, co się tutaj dzieje. Jeśli masz jakieś pytania, zostaw komentarz.

Aaron Plocharczyk
źródło
0

Pętla przechodzi przez tę samą tablicę, w której indeks zmienia się po usunięciu elementu z tablicy. Poniżej znajduje się przykład, w którym można przeglądać opcje bez indeksu i usuwać go z tablicy.

var selectOptions = document.querySelectorAll('#remove-option>option');
selectOptions.forEach(function(selectOption) {
  selectOption.remove();
  selectOption = null;
});

Oto skrzypce

kichus14
źródło