[Rails][Ajax]ajax로 불러온 div 영역내의 버튼의 id는 인식되지 못하나요?

조회수 6286회

안녕하세요 ruby on rails 를 공부하고 있는 학생입니다. 최근 Ajax에 관심이 생겨서 학습하던 도중 이유를 알 수 없는 오류가 생겨서 질문드립니다.

제가 구성한 페이지는 1차로 Ajax를 이용해서 category 클래스를 가진 버튼을 누르면 menulist라는 곳이 드랍다운 메뉴로 형태가 됩니다. 드랍 다운 내부에는 input text 2개와 버튼 1개가 들어있습니다. 버튼의 class에 insert를 추가하고 ajax 된 상태에서 다시 ajax를 추가했습니다. 하지만 ajax가 작동하지 않네요.

기존 형식과 같은 Ajax 코드인데 첫 화면에서는 ajax를 통하여 데이터가 제대로 전송되었는데, ajax를 통해서 생긴 버튼으로는 script가 실행되지 않습니다. 원래 자바스크립트를 통해 생긴 버튼은 자바스크립트를 이용할 수 없는 건가요? 두서없이 설명한 것 같아 죄송합니다. c9을 하시는 분이라면 아이디 남겨주세요. ㅠㅠ 이렇게밖에 설명 못드려서 죄송합니다.

<script>
    $(".category").click(function(){
        send_value=this.value;
        alert(send_value);
        $.ajax({
            method: "POST",
            url: "/setting/menusetting",
            data: { categoryid : send_value},
            dataType : 'json'
        })
            .done(function (data) {
                $("#table").html(" ");
                $("#table").html("<table border='1' style='font-weight:bold; text-align:center;'>"+
                    "<tr class='row' style='font-size:20px;'>" + "<td class='col-md-4'>이름</td>" +
                    "<td class='col-md-3'>가격</td>" + "<td class='col-md-3'>비고</td>" +
                    "<td class='col-md-2' style=' font-size:15px;'>수정/삭제</td></tr>");
                for (var i=0;i<data.length;i++) {
                    $( "#table").append( "<table border='1' style='text-align:center;'>"+
                        "<tr class='row' style='font-size:20px;'>" +
                        "<td class='col-md-4' style='text-align:center;'>"+ data[i].name +"</td>" +
                        "<td class='col-md-3'>"+ data[i].price+"</td>" +
                        "<td class='col-md-3' style='text-align:center;'></td>" +
                        "<td class='col-md-2' style='text-align:center; font-size:13px;'>" +
                        "<a href='/setting/menu_change1/"+ data[i].id +"'>수정</a>" +
                        "<a href='/setting/menu_destroy/"+ data[i].id +"'>삭제</a></td>"+
                        "</tr></table>"); }
                $("#menulist").html("<label for='exampleInputEmail1'>메뉴 목록</label>" + "<div class='dropdown'>" +
                    "<button class='btn btn-default dropdown-toggle' type='button' id='dropdownMenu1' data-toggle='dropdown' aria-haspopup='true' aria-expanded='true'>" +
                    "<i class='fa fa-asterisk' aria-hidden='true'></i><span class='caret'></span></button>"+
                    "<ul class='dropdown-menu' aria-labelledby='dropdownMenu1'>"+
                    "<div class='form-group' style='float:left;'><label for='exampleInputEmail1' style='float:left;'>메뉴명</label>"+
                    "<input type='text' class='form-control' id='menu_name' style='width:200px;'>"+
                    "<label for='exampleInputEmail1' style='float:left;'>가격</label>"+
                    "<input type='text'  class='form-control' id='menu_price' style='width:200px;'>"+
                    "<button type='submit' class='btn btn-default insert'  value='"+ send_value + "'>입력</button></div></ul><hr>"
                );
            });
    });


    $("#all").click(function(){
        $("#menu").html("<%@category.each do |c|%>"+"<% c.menu.each do |m| %>"+
            "<div class='col-lg-3' style='padding:5px;'>"+
            "<button class='btn btn-defalut' id='showmenuid' type='submit' value='<%= m.id %>' name='menuid' style='background-color:white; height:100px; width:130px; box-shadow:0 2px 2px 0 darkgray;'><b><%=m.name%></b><br><%=m.price%> 원</button>"+
            "</div>"+
            "<% end %>"+"<% end %>");
        $("#menulist").html("<label for='exampleInputEmail1' style='padding-bottom:33px;'>메뉴 목록</label>"+
            "<hr>");
        $("#table").html("<table border='1' style='font-weight:bold; text-align:center;'>"+
            "<tr class='row' style='font-size:20px;'>" + "<td class='col-md-4'>카테고리</td>" +
            "<td class='col-md-4'>이름</td>" + "<td class='col-md-2'>가격</td>" +
            "<td class='col-md-2' style=' font-size:15px;'>수정/삭제</td></tr>" +
            "</table><% if @category.present? %><% @category.each do |m|%>" +
            "<% m.menu.each do |y| %>" +
            "<table border='1' style='text-align:center;'>"+
            "<tr class='row' style='font-size:20px;'>" +
            "<td class='col-md-4' style='text-align:center;'><%=m.name%></td>" +
            "<td class='col-md-4'><%=y.name%></td>" +
            "<td class='col-md-2' style='text-align:center;'><%=y.price %></td>" +
            "<td class='col-md-2' style='text-align:center; font-size:13px;'>" +
            "<a href='/setting/menu_change1/<%=y.id%>'>수정</a>" +
            "<a href='/setting/menu_destroy/<%=y.id%>''>삭제</a></td>"+
            "</tr></table><%end%><%end%><%else%><%end%>");
    });





    $(".insert").click(function(){
        send_id=this.value;

        $.ajax({
            method: "POST",
            url: "/setting/menu",
            data: { categoryid : 1

            },
            dataType : 'json'
        })
            .done(function (data) {
                $("#table").html(" ");
                $("#table").html("<table border='1' style='font-weight:bold; text-align:center;'>"+
                    "<tr class='row' style='font-size:20px;'>" + "<td class='col-md-4'>이름</td>" +
                    "<td class='col-md-3'>가격</td>" + "<td class='col-md-3'>비고</td>" +
                    "<td class='col-md-2' style=' font-size:15px;'>수정/삭제</td></tr>");
                for (var i=0;i<data.length;i++) {
                    $( "#table").append( "<table border='1' style='text-align:center;'>"+
                        "<tr class='row' style='font-size:20px;'>" +
                        "<td class='col-md-4' style='text-align:center;'>"+ data[i].name +"</td>" +
                        "<td class='col-md-3'>"+ data[i].price+"</td>" +
                        "<td class='col-md-3' style='text-align:center;'></td>" +
                        "<td class='col-md-2' style='text-align:center; font-size:13px;'>" +
                        "<a href='/setting/menu_change1/"+ data[i].id +"'>수정</a>" +
                        "<a href='/setting/menu_destroy/"+ data[i].id +"'>삭제</a></td>"+
                        "</tr></table>"); }
                $("#menulist").html("<label for='exampleInputEmail1'>메뉴 목록</label>" + "<div class='dropdown'>" +
                    "<button class='btn btn-default dropdown-toggle' type='button' id='dropdownMenu1' data-toggle='dropdown' aria-haspopup='true' aria-expanded='true'>" +
                    "<i class='fa fa-asterisk' aria-hidden='true'></i><span class='caret'></span></button>"+
                    "<ul class='dropdown-menu' aria-labelledby='dropdownMenu1'>"+
                    "<div class='form-group' style='float:left;'><label for='exampleInputEmail1' style='float:left;'>메뉴명</label>"+
                    "<input type='text' class='form-control' id='menu_name' style='width:200px;'></div><div class='form-group'>"+
                    "<label for='exampleInputEmail1' style='float:left;'>가격</label>"+
                    "<input type='text' class='form-control' id='menu_price' style='width:200px;'>"+
                    "<button type='submit' class='btn btn-default insert' value='"+ send_value + "'>입력</button></div></ul></div><hr>"
                );
            });
    });
</script>
  • 새로 추가한 엘리먼트는 이벤트가 바인딩이 안되어있기 때문에 추가했을 때 원하는 이벤트를 바인딩해야 합니다. 코드를 안봐서 해결책이 아닐 수도 있지만 체크해보세요. 알 수 없는 사용자 2017.4.12 19:33

2 답변

  • script는 top에서 bottom으로 순차적으로 실행됩니다. 그리고 함수는 호출되는 시점에 실행이 되죠.

    .click 함수를 이용해서 click이벤트를 바인딩하는 시점은 화면이 열릴 때 입니다. 이 시점에서는 .insert나 #all jquery object가 없는 것으로 보입니다. .insert나 #all 이 body에 append되는 시점은 ajax 호출 후 done 메서드에 인자로 등록한 콜백함수가 실행되는 시점이 되겠죠.

    결론은 위 댓글에 달아주신것 처럼 click 이벤트 바인딩 시점이 class="insert"와 id="all" 을 가진 html엘레먼트가 body에 존재하기 전에 이벤트를 바인딩해서 입니다.

    최소한의 수정으로 가장 쉽게 해결할 수 있는 방법은 click이벤트 바인딩하는 부분을 함수로 만들고 done의 콜백함수 제일 마지막에 함수를 호출해 주면 되겠네요.

    추가로 공부를 하신다고 해서 여담을 드리자면..

    이왕 jquery를 사용하신다면 jquery를 적극 활용하는 쪽을 추천해 드립니다. string 형식의 html내용을 html메서드로 붙이는 방법은 그리 좋은 방법이 아닙니다. 다른사람이 소스를 보고 분석하기도 힘들고 수정도 어렵고 뭔가 오류가 발생하면 찾기도 힘듭니다.

    var $table = $("<table/>").attr({border:1}).css({"font-weight": "bold", "text-align":"center"});
    $("#table").append($table);
    

    위 같이 메서드를 통해 jquery object를 생성하여 append하는 것을 권장해 드려요. 당연 이벤트 같은 것도 메서드를 통해 bind해야 합니다.

    var $btn = $("<button/>").text("버튼").click(function(){
        alert("버튼입니다.");
    });
    $("sometag").append($btn);
    
    • (•́ ✖ •̀)
      알 수 없는 사용자
    • 자바스크립트와 J쿼리의 기초도 익히지 못한 학생이 구상한 코드라 이해하기 힘드셨을거라 생각됩니다. 그런데도 나아갈 방향을 제시해주신 것만으로도 너무 감사합니다. 학기중이라 시간내기는 힘들지만 방학떄 자바스크립트와 제이쿼리 공부 하겠습니다 감사합니다 tongil 2017.4.13 23:56
  • 답변자가 직접 실행해 볼 수 있게 소스 전체를 적어주시거나, 아니면 아예 요약된 소스를 적어주시는게 좋습니다. 읽기가 너무 힘드네요 ㅠㅠ

    혹시 아래와 같은 문제가 아닌지 확인해보세요.

    이벤트 핸들러를 할당할 때 원하는 요소를 직접 선택하지 마시고 부모 요소를 선택하는 방식으로 하세요. 이벤트 버블링을 이용한 방식입니다. 예를 들어 마크업이 다음과 같을 때:

    <div>
        <button type="button" onclick="appendSomeElement()">push me</button>
    </div>
    
    $(document).ready(function() {
        $('#all').click(clickHandler1); // 이 스크립트가 실행될 시점에는 id="all"인 요소가 없으므로 바인딩이 제대로 되지 않음.
    
        $('div').on('click', '#all', clickHandler2); // 이렇게 해보세요.
    });
    
    function appendSomeElement() {
        // id="all"인 요소를 <div> 하위에 append
    }
    
    • 정말 감사합니다. 레일즈로 웹을 공부하는 학생인데 자바스크립트나 J쿼리 기초지식이 부족해서 이런 문제가 생겼네요 열심히 공부하겠습니다! tongil 2017.4.13 23:53

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)