1. 상황

이미 존재하는 버튼에 click 이벤트를 JavaScript로 동적으로 넣을 경우 addEventListener를 사용할 수 있다.

이벤트 발생시 동작하는 function에 매개변수를 각 열마다 다르게 전달하기 위해, 매개 변수를 동적으로 할당해야한다.

그러나 JavaScript는 비동기로 동작한다는 점을 잘 고려하지 못하여 시행착오 끝에 해당 기능을 개발할 수 있었다.

기초적인 기능이라 그런지 오히려 자료들이 많지 않았기에 해결 과정을 정리해둔다.

 

2. 과정

버튼0 부터 버튼 3까지 존재하는 버튼i를 만들어서

버튼i을 클릭하면 "button click {i}"를 로그로 남기는 기능을 만드는 것이 목표이다.

 

2.1. 테스트 1

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <title>자바스크립트 테스트 페이지</title>
</head>

<body>
<script>
window.onload = function() {
    for (var i = 0; i < 4; i++) {
        let element = document.getElementById('button' + i);
        console.log("i = " + i);

        element.addEventListener('click', function() {
            //핵심로직
            console.log("button click " + i);
        });
    }
}
</script>

<button type="button" id="button0">버튼0</button>
<button type="button" id="button1">버튼1</button>
<button type="button" id="button2">버튼2</button>
<button type="button" id="button3">버튼3</button>

</body>

</html>

window.onload()를 보면  for문 안에 addEventListener를 적용하고 있다.

그러나 for문과 addEventListener가 비동기적으로 적용이 되는 점을 고려하지 못했다.

결과적으로 어떤 버튼을 누르던 "button click 4"를 반환해서 원하는데로 동작하지 않는다.

 

그렇다면 핵심 로직("button click {i}"를 로그로 남기기)을 별도의 function으로 감싸면 

function이 따로 적용되어 위 문제가 해결되지 않을까?

 

2.2. 테스트 2

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <title>자바스크립트 테스트 페이지</title>
</head>

<body>
<script>
window.onload = function() {

    for (var i = 0; i < 4; i++) {
        let element = document.getElementById('button' + i);
        console.log("i = " + i);
        
        element.addEventListener('click', sendITest1(i));
    }

}

function sendITest1(i) {
    //핵심로직
    console.log("button click " + i);
}

</script>

<button type="button" id="button0">버튼0</button>
<button type="button" id="button1">버튼1</button>
<button type="button" id="button2">버튼2</button>
<button type="button" id="button3">버튼3</button>

</body>

</html>

addEventListener에 들어가는 핵심 로직을 sendITest1 함수에 넣고,

sendITest1를 addEventListener에 전달하고 있다.

 

결과적으로 위 addEventListener가 실행되는 시점에 sendITest1 까지 바로 실행이 되어 

모든 버튼들이 그때 클릭이 되는 것처럼 인식되고 

html을 여는 시점에 "button click {i}" 로그가 전부 찍히고 만다.

 

그렇다면 addEventListener 자체를 별도의 함수로 감싸서 for문에서 이를 호출하는 것은 어떨까?

 

2.3. 테스트 3

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <title>자바스크립트 테스트 페이지</title>
</head>

<body>
<script>
window.onload = function() {

    for (var i = 0; i < 4; i++) {
        console.log("i = " + i);
        sendITest2(i)
    }

}

function sendITest2(i) {
    let element = document.getElementById('button' + i);
    element.addEventListener('click', function() {
        //핵심로직
        console.log("button click " + i);
    });
}

</script>

<button type="button" id="button0">버튼0</button>
<button type="button" id="button1">버튼1</button>
<button type="button" id="button2">버튼2</button>
<button type="button" id="button3">버튼3</button>

</body>

</html>

for문에서는 단순히 sendITest2를 호출하기만 하고, sendITest2에서 addEventListener를 버튼에 추가한다.

결과적으로 위 코드가 내가 원하는데로 동작하였다!

 

addEventListener 자체를 for문과 분리하여,

원하는 매개변수가 제대로 전달되게 함과 동시에

addEventListener가 바로 실행되지 않게 하였다.

 

3. 번외

addEventListener뿐만 아니라 createElement를 이용하더라도 동일한 문제에 만난다.

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <title>자바스크립트 테스트 페이지</title>
</head>

<body>
<script>
window.onload = function() {

    for (var i = 0; i < 4; i++) {
        let btn = document.createElement("button");
        btn.onclick = function() { testFunction(i); };
        btn.innerHTML = "button" + i;
        document.body.append(btn);
    }

}

function testFunction(i) {
    //핵심로직
    console.log("button click " + i);
}

</script>

</body>

</html>

위의 경우에도 어떤 버튼을 누르던 "button click 4"를 반환한다.

 

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <title>자바스크립트 테스트 페이지</title>
</head>

<body>
<script>
window.onload = function() {

    for (var i = 0; i < 4; i++) {
        testFunction1(i);
    }

}

function testFunction1(i) {
    let btn = document.createElement("button");
    btn.innerHTML = "button" + i;
    btn.onclick = function() { testFunction2(i); };
    document.body.append(btn);
}

function testFunction2(i) {
    //핵심로직
    console.log("button click " + i);
}

</script>

</body>

</html>

앞에서와 같이 function을 따로 호출하도록 감싸주면 원하는데로 동작한다!

+ Recent posts