Вставка элементов в массив с помощью EventListener

Я пытаюсь обновить массив значениями, как только пользователь нажимает на элемент в DOM. Кажется, что элементы помещаются в массив внутри анонимной функции, но вне функции массив все еще пуст. Как я могу это исправить? Вот код JavaScript:

function getSelection() {
    var selections = [];

    var container = document.getElementById("main-container");
    var choices = document.querySelectorAll('li');

    choicesLength = choices.length;

    for(var i = 0; i < choicesLength; i++) {

        choices[i].addEventListener("click", function(){
            var position = this.getAttribute("value");
            selections.push(position);
            // logs array and updates with each click 
            console.log(selections);
        });
    }       

    // logs empty array
    console.log(selections);

}

В основном, после того, как элементы нажаты, основной массив должен быть обновлен в соответствии с тем, что они щелкнули.

Любая помощь будет оценена.

Спасибо

4 ответа

Функция, которую вы передаете addEventListener не будет работать, пока не произойдет событие.

Вы не можете нажать ни один из пунктов списка до console.log который запускается сразу после того, как назначение срабатывает.

В основном, после того, как элементы нажаты, основной массив должен быть обновлен в соответствии с тем, что они щелкнули.

... и вот что будет. Посмотрите на результаты console.log внутри обработчика кликов.

Это о Javascript Scoping, вы можете больше об этом здесь:
Узнайте больше о Javascript Scoping и подъем

Первый console.log(selection) является локальным, в то время как последний console.log(selection) является глобальным, они не совпадают, поэтому он пуст. Вот отредактированная форма моего решения:

function getSelection() {
  var selections = [];
  var container = document.getElementById("main-container");
  var choices = document.querySelectorAll('li');
  choicesLength = choices.length;
  for (var i = 0; i < choicesLength; i++) {

    choices[i].addEventListener("click",pushArray(i));
  }
  
  function pushArray(elm) {
  var position = choices[elm].getAttribute("value");
  selections.push(position);
  // logs array and updates with each click 
 console.log(selections);
}
  // logs empty array
  console.log(selections);
}


document.body.addEventListener("load", getSelection());
<ul>
  <li value="1">1</li>
  <li value="2">2</li>
  <li value="3">3</li>
  <li value="4">4</li>
  <li value="5">5</li>
  <li value="6">6</li>
  <li value="7">7</li>
  <li value="8">8</li>
  <li value="9">9</li>
  <li value="10">10</li>
</ul>

В основном двигаться selections отус функции getSelection и сделать это публичным.

var selections = [];

function getSelection() {
    var container = document.getElementById("main-container");
    var choices = document.querySelectorAll('li');
    choicesLength = choices.length;
    for(var i = 0; i < choicesLength; i++) {
        choices[i].addEventListener("click", function(){
            var position = this.getAttribute("value");
            selections.push(position);
            console.log(selections);
        });
    }       
    console.log(selections);
}
window.onload = getSelection;

// access selections outside of getSelection()
setInterval(function () {
    if (selections.length < 2) {
        console.log('length is smaller than two.');
    }
}, 1500);
<ul><li value="1">1</li><li value="2">2</li><li value="3">3</li><li value="4">4</li><li value="5">5</li><li value="6">6</li></ul>

В дополнение к моему комментарию, я думаю, что замыкания могут решить эту проблему довольно эффективно.

Я не проверял следующий код:

function getSelection() {
this.selections = [];

var container = document.getElementById("main-container");
var choices = document.querySelectorAll('li');

choicesLength = choices.length;
var that = this;
for(var i = 0; i < choicesLength; i++) {

    choices[i].addEventListener("click", function(){
        var position = this.getAttribute("value");
        that.selections.push(position); //Explicitly specify context
        // logs array and updates with each click 
        console.log(that.selections);
    });
}       

return function(){
   this.selections;
}
}

Вы называете getSelection функционировать так:

var getUpdatedArray = getSelection();
//At a later stage when you want the array just do:
getUpdatedArray(); //This should return the selections array.

Я явно связываю selections массив для вашей функции, выполнив this.selections = [] а затем установить этот контекст внутри слушателей щелчка, выполнив var that = this,

Чтобы повторить проблему:

Вы были обязательными слушателями событий в вашем getSelection метод, который вызывается только один раз. Однако щелчки могут произойти в любое время позже. Так что вам нужно обеспечить две вещи:

  1. selections массив, указанный в click Обработчик события - это тот, который определен в области getSelection метод.
  2. Каким-то образом, сохранить рамки getSelection метод даже после того, как он выполнен.

Замыкания, волшебным образом решают обе эти проблемы.:)

Хорошая отправная точка для того, почему использовать закрытие - это.

Другие вопросы по тегам