Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Присвоить события внутри цикла (https://javascript.ru/forum/events/65741-prisvoit-sobytiya-vnutri-cikla.html)

Koyf 05.11.2016 19:19

Присвоить события внутри цикла
 
Уважаемые знатоки, прошу помочь. Как присвоить соответствующей кнопке событие, которое выведет значение из соответствующего поля ввода в консоль?
Вот что имею:
for(i=0;i<3;i++){
  inp = document.createElement('input')
  btn = document.createElement('input')
  inp.className='inpt'
  btn.className='but'
  btn.type='button'
  btn.value = 'click'
  document.body.appendChild(inp)
  document.body.appendChild(btn)
  document.getElementsByClassName('but')[i].onclick = function(){
    console.log(document.getElementsByClassName('inpt')[i].value)
  }
}

Aetae 05.11.2016 19:40

document.getElementsByClassName('inpt')[i].value
// ->
this.value

fuckingquest 05.11.2016 20:05

Koyf,
Выше правильный вариант подсказали, но вообще ваша проблема в том, что при создании всех коллбеков на onclick они замкнуты на одно и то же окружение(в данном случае -- глобальный объект), соответственно i в них всех вычисляется в последнее значение, вернувшееся из цикла.
вот наглядный пример:
arrayOfFunctions = []
i = 10
while(i--) arrayOfFunctions.push(function(){console.log(i)})
i = "foo"
arrayOfFunctions.forEach(function(f){f()})



//>>>> foo
//>>>> foo
//>>>> foo
//>>>> foo
//>>>> foo
//>>>> foo
//>>>> foo
//>>>> foo
//>>>> foo
//>>>> foo

Не всегда очевидное для новичков поведение.
Просто имейте это в виду.

UPD а добится желаемого эффекта довольно легко: просто компилировать ф-ции на лету:
arr = ["a", "b", "c"]
functions = []

i = -1
while(i < 2){ ++i; functions.push(Function("f", "console.log(arr[" + i + "])")) }
i = -1
while(i < 2){ ++i; functions.push(function(f){console.log(arr[i])}) }

functions.forEach(function(f){f()})


//>>>> a
//>>>> b
//>>>> c
//>>>> c
//>>>> c
//>>>> c

можно еще создавать дополнительные замыкания на каждой итерации или в ES6 можете еще воспользоваться декларацией переменных с блочной видимостью, но злоупотреблять этим не следует, так как это серьезный жер памяти.

Koyf 05.11.2016 21:33

Всем спасибо за помощь, наконец таки разобрался)
Вдруг кому пригодится
for(i=0;i<3;i++){
  inp = document.createElement('input')
  btn = document.createElement('input')
  inp.className='inpt'
  btn.className='but'
  btn.type='button'
  btn.value = 'click'
  document.body.appendChild(inp)
  document.body.appendChild(btn)
  document.getElementsByClassName('but')[i].onclick = Function('f'+i,'console.log(document.getElementsByClassName("inpt")['+i+'].value)')
}

Aetae 05.11.2016 21:55

Koyf, нет не в этом.
Создание функций из текста - ужасное решение.

fuckingquest 05.11.2016 23:43

Aetae,
Что в нем плохого?
Я, кстати, не спорю, что для данного кейза Ваше решение лучше, о чем упомянул, но в общем случае, им не обойдешься. А из всех вариантов, которые тут возможны, которые сводятся, по сути, к 3-м случаям: создание отдельной структуры указателей(слишком сложно для этого), создание отдельных окружений для каждого коллбека, явно или или подковерно(с блочным сахаром типа let), что ведет к оверхеду по памяти и тормозам при массовом применении и компиляция на ходу, последнее явно предпочтительней


Часовой пояс GMT +3, время: 14:34.