Entfernen von Optionen aus Select-Tag in Vanilla JavaScript mit der Schleife "for .. of"

10

Wenn Sie versuchen, Optionen aus der Auswahl zu entfernen, bleibt immer eine übrig. Warum?

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

Dieser JS funktioniert nicht:

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

Und das funktioniert auch nicht:

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

Ich weiß, dass es andere Lösungen gibt, um dies zu erreichen, aber ich würde gerne verstehen, warum es nicht so funktioniert, wie es soll

Piotr
quelle

Antworten:

7

Die .optionsSammlung ist (leider) live . Wenn Sie also die Elemente der Live-Sammlung einzeln durchlaufen und .removejede einzelne auswählen, wird jede ungerade beibehalten. (Wenn Sie beispielsweise das erste Element entfernen, wird das [0]dritte Element der Sammlung sofort zum nächsten Element in der Sammlung - was früher war, [1]wird [0](und sobald Sie zum nächsten Index bei gehen [1], wird das neue Element an Position 0 wird nicht wiederholt)

Verwenden Sie document.querySelectorAllstattdessen, um eine statische Sammlung zurückzugeben:

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>

Sie können sich auch in ein (statisches) Array verteilen, bevor Sie Elemente entfernen ::

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>

Eine weitere Option, die zufällig funktioniert, weil die Sammlung live ist (aber wahrscheinlich nicht verwendet werden sollte, da sie nicht intuitiv ist):

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>

Bestimmte Leistung
quelle
3

Sie entfernen Elemente aus einem Array, während Sie das Array durchlaufen. Also hast du:

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

Dann entfernen Sie das Element bei Index 0, der "Eins" ist, und lassen Sie mit:

["two","three"]

Als nächstes entfernen Sie das Element bei Index 1, das "drei" ist, und lassen Sie mit:

["two"]

Bei Index 2 befindet sich kein Element, daher stoppt die Schleife.

Durchlaufen Sie das Array stattdessen in umgekehrter Reihenfolge :

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>

symlink
quelle
Das .optionsist kein Array, das die Ursache des Problems ist, sondern eine HTMLCollection, die live ist. Wäre es ein Array, wäre es statisch und es würde keine Probleme geben.
Bestimmte Leistung
1
@CertainPerformance Elemente aus einem Array entfernen , wie Sie durchlaufen sie tut das Problem , weil ich gezeigt habe.
Symlink
1
@CertainPerformance Ein HTMLOptionsCollectionObjekt verhält sich in diesem Kontext wie ein Array.
Symlink
2

Ich sehe, dass Ihr Hauptziel darin besteht, den Prozess zu verstehen, der dies verursacht. Dies sollte das Problem für Sie veranschaulichen:

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) + ".");

Diese Schleife durchläuft genau die gleiche Art von Prozess, die Ihre "for .. of" -Schleife durchläuft, um Ihnen im Endergebnis Extras zu hinterlassen. Das Problem ist, dass es seine eigenen Indizes zerstört, während es sie durchläuft, wodurch sich der Wert ändert, auf den es isich wirklich bezieht. Wenn ich mit diesem Problem konfrontiert bin, durchlaufe ich das Array gerne rückwärts, damit ich von meiner eigenen Zerstörung nicht betroffen bin.

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) + ".");

Ich hoffe, das hilft Ihnen zu verstehen, was hier gründlich vor sich geht. Wenn Sie Fragen haben, können Sie mir gerne einen Kommentar hinterlassen.

Aaron Plocharczyk
quelle
0

Sie durchlaufen dasselbe Array, in dem sich der Index ändert, sobald Sie das Element aus dem Array entfernen. Unten finden Sie ein Beispiel, in dem Sie Optionen ohne Index durchlaufen und aus dem Array entfernen können.

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

Hier ist die Geige

kichus14
quelle