[javascript] 이벤트 핸들러 (with for문)

2-pi-r·2023년 6월 26일
0

요약

  • for문으로 이벤트 핸들러를 추가하면, 논리적으로 봤을 때는 코드에 문제가 없어 보이지만 실제로는 제대로 동작하지 않는다.
  • 이벤트 핸들러 내에서 사용한 인덱스에는 모두 'for문을 다 돈 후의 인덱스' 값이 들어가기 때문이다.

예시 상황

html에서 jinja2 for문으로 버튼을 만들었다. 각 버튼에 이벤트 핸들러를 추가해야 하는데, 이것도 for문으로 해볼까?

temp.py 코드

from flask import Flask, render_template
app= Flask(__name__)

@app.route('/')
def hello_world():
    return render_template("temp.html")

app.run(port=5000, debug=True)

temp.html 코드

{% for idx in range(5) %}
    <button name="idx_button">{{idx}}</button>
{% endfor %}

<script>
    const button_list = document.getElementsByName("idx_button");
    for(var i = 0; i < button_list.length; i++){
        button_list[i].addEventListener("click", function(e){ 
            console.log("버튼 :", e.target.innerHTML, ", i :", i)
        });
    }
</script>

문제

console.log를 찍어서 확인해보면 다음과 같다.

원래 의도한 바는
버튼 0을 누르면 → 0이 찍히고
버튼 1을 누르면 → 1이 찍히는 것이다.

하지만 실제로는 어떤 버튼을 누르든 5가 찍혔다.

이유

이 5는 어디서 온 것일까? 바로, for문을 다 돌고 난 후의 i값이다.

생각해보라. 만약 현재 i가 4라고 하자. for문 안의 코드를 실행한 후, 증감식에 따라 i는 5가 된다. 이는 조건식에서 false이므로 for문을 탈출한다. 그러니까 현재는 i가 5다.

왜 저 코드가 제대로 작동하지 않는지까지는 모르겠다. 확실한 건 이렇게 5가 들어간다는 것이다.

해결방법

다른 좋은 방법이 있을 수도 있겠지만, 일단 내가 해결한 방법은 다음과 같다.

javascript에서 list를 배열(array)로 바꾼 후,
이벤트 핸들러 내에서 i를 직접 사용하지 않고 그때마다 구해준 것이다. array에서 해당 이벤트 타겟과 같은 값을 찾아서 그 배열의 인덱스를 사용하는 방식으로 말이다.

temp.html 코드

{% for idx in range(5) %}
    <button name="idx_button">{{idx}}</button>
{% endfor %}

<script>
    const button_list = document.getElementsByName("idx_button");
    
    '{# 주석 : button_arr 구하기 #}'
    var button_arr = []
    for (var i = 0; i < button_list.length; i++) {
        button_arr.push(button_list[i]);
    }
    console.log(button_arr)
    '{# 주석 : 이벤트 핸들러 추가 #}'
    for(var i = 0; i < button_list.length; i++){
        button_list[i].addEventListener("click", function(e){ 
            const idx = button_arr.indexOf(e.target); '{# 주석 : idx 구하기 #}'
            console.log("버튼 :", e.target.innerHTML, ", i :", idx)
        });
    }
</script>

0개의 댓글