자바스크립트 실행 순서 질문드립니다.

2019. 02. 02. 11:53

먼저 해당 HTML 문서에 div 내용을 넣고 웹문서를 실행서 해당 div 내용을 클릭하면 해당 스크립트가 호출이 잘됩니다.

문제는 이렇게 하지않고 파싱을해서 들고온 내용을 해당 div에 출력을고 해당 div 를 클릭을하면 오류도 없고 반응도 없습니다. 혹시나 싶어서 개발자 도구를 키고 해당 스크립트 코드(4주석영역)를 다시 주입하고 div 클릭을 하면 정상적으로 해당 스크립트가 호출이 되더라구요... 실행 순서 문제 인것같은데 도와주세요.

<!--1. 여기있는 스크립트 가 제일 먼저 실행이되고 -->
<script 
    src="https://code.jquery.com/jquery-3.3.1.js" 
    integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" 
    crossorigin="anonymous"></script> 
<script> 
//2. 여기있는 스크립트 가 두번쨰로 먼저 실행이되고
$.getJSON('https://', function(data) { 
  ----(생략)---- 
  $('.pop-wrapper').append('<input type="checkbox" id="'+code+'">'+ 
          '<div class="items '+code+'"><label for="IMG'+code+'">....</label></div>'); 
}); 
</script> 
<body> 
<div class="pop-wrapper"> 
  <!--3. (2)스크립트 내용을 출력하는부분임(직접 입력하고 웹문서를 실행후 클릭하면 (4)스크립트가 실행이됨) --> 
  <div class="items aTest1"><label for="aTest1">.....</div> 
</div> 
<script> 
//4. (3)출력 하는 내용을 가지고 실행 하는 스크립트임 해당 스크립트가 실행이안됨 
$('.items').click(function(){ 
  var ce = $(this).find("label").attr("for"); 
} 
</script> 
</body> 
공유하고 돈벌기 ♥︎

총 2개의 답변이 있습니다.

질문자 채택 답변
OpenSG 수석 컨설턴트

HTML 문서는 내부 엘리먼트의 순서대로 로딩됩니다. 즉 2번 스크립트가 실행될 때는 아래쪽 body 요소 안쪽은 아직 로딩되지 않은 상태입니다. 하지만 여기서 $.getJSON으로 비동기 AJAX 요청을 하고 서버로부터의 응답을 수신하는 시점에는 body 내부의 요소가 만들어져 있으므로 출력이 되겠네요.

그런데 문제는 4번을 등록하는 시점에는 $.getJSON 으로 비동기 요청한 후 서버로부터의 응답이 수신되었을 때 실행되는 코드 (div.items 요소들을 생성하는 코드)가 실행되지 않았겠지요. 따라서 4번 시점에서는 존재하지 않는 요소들에 대해 이벤트를 설정하려고 시도한 것이 됩니다.

이 문제를 해결하려면 코드를 다음과 같이 수정해야 겠습니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div class="pop-wrapper"> 

    </div> 
    <script src="https://code.jquery.com/jquery.js"></script>
    <script>
    var template = "<div class='items aTest'><label for='${no}'>${name}</label></div>";
    $.getJSON("data.json").done(function(data) {
        var str = "";
        for (var i=0; i < data.length; i++) {
            str += template.replace("${no}", data[i].no).replace("${name}", data[i].name);
        }
        $('.pop-wrapper').append(str);
        $('.items').click(function(){ 
            var ce = $(this).find("label").attr("for"); 
            alert(ce);
        })
    })
    </script>
</body>
</html>

.pop-wrapper 요소 내부에 컨텐츠를 출력한 후에 이벤트를 설정하는 겁니다. 새롭게 컨텐츠가 출력되면 다시 이벤트를 설정해야 합니다. 매번 이벤트 설정이 번거롭다면 이벤트 위임(Event Delegation)을 고려하세요 jQuery Event Delegation으로 검색하면 쉽게 찾을 수 있을 겁니다.

P.S : 답글을 쓰고 있는 동안에 zerocho님이 이벤트위임에 대해 쓰셨네요.. 그래서 앞의 코드를 이벤트 위임으로 바꿔보았습니다. <script> 안쪽만을 변경합니다.

    <script>

    $('.pop-wrapper').on('click', '.items', function(){   
        var ce = $(this).find("label").attr("for"); 
        alert(ce);
    })

    var template = "<div class='items aTest'><label for='${no}'>${name}</label></div>";
    $.getJSON("data.json").done(function(data) {
        var str = "";
        for (var i=0; i < data.length; i++) {
            str += template.replace("${no}", data[i].no).replace("${name}", data[i].name);
        }
        $('.pop-wrapper').append(str);
    })
    </script>

그리고 다음은 사용했던 데이터입니다. data.json 파일

[
    { "no":1, "name":"Apple" },
    { "no":2, "name":"Pear" },
    { "no":3, "name":"Kiwi" },
    { "no":4, "name":"Grape" }
]

2019. 02. 02. 13:23
62
마이핏 CTO

getJSON의 콜백 부분이 비동기라 제일 늦게 실행됩니다. .item에 클릭 이벤트를 걸 때 .item태그가 없습니다.

이때 쓰는 기법이 이벤트델리게이션으로 4번 부분을 $(document).on('click', '.item', 콜백)

하시면 됩니다.

2019. 02. 02. 13:04
40