자바스크립트 실행 순서 질문드립니다.
먼저 해당 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>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" } ]getJSON의 콜백 부분이 비동기라 제일 늦게 실행됩니다. .item에 클릭 이벤트를 걸 때 .item태그가 없습니다.
이때 쓰는 기법이 이벤트델리게이션으로 4번 부분을 $(document).on('click', '.item', 콜백)
하시면 됩니다.