6

From looking at other posts I've tried to add live() and on() to my code but the click function only works once and then wont work anymore. Can someone point out what I'm doing wrong. Here is my latest code:

<script language="javascript">
//Used to delete a step from the database after confirming with user
$(document).ready(function(){
    $("#success_message2").hide();
    $(".delete_it").on('click',function() {
    var answer = confirm('Are you sure you want to delete this step?');
    if (answer){
          var data = {
              'hospid': '<? echo $hospid; ?>',
              "step_id" : $(this).parent().attr("name")
              }; 
        $.post("../php/progress_steps_delete.php",
                data,
                function (data) {
                    if (data.success) {
                        $("#success_message2").show('slow');
                        setTimeout(function () {
                            $("#success_message2").hide('slow');
                        }, 5000);
                        $('#step_list').html(data.success);
                    } else {
                        alert('not done');
                        $("#non-grid").prepend(data.error);
                    }
                }, "json");
    }
});
});
</script>

Apologies, here is the html

<body>
<div id="body-wrapper">
  <?php include_once(getBasePath()."site_hospital_files/elements/navbar.php"); ?>
  <div id="main-content">
    <div class="content-box">
      <div class="content-box-header">
        <h3>Progress Steps</h3>
      </div>
      <div class="content-box-content">
        <div class="msg-status div_message" id="success_message">New step added successfully!</div>
        <div class="msg-status div_message" id="success_message1">New List Order Updated!</div>
        <div class="msg-status div_message" id="success_message2">Step Deleted!</div>
        <div id="non-grid">
          <form method="post" name="upload_form" id="upload_form">
            <fieldset style="height:100px;  margin-left:25px; margin-top:15px; background-color:#FFF;">
              <legend style="padding:2px;">Add a Step</legend>
              <div class="column-left" style="width:50%;">
                <label class="space">Step Name</label>
                <input class="text-input tall-input required alnum" type="text" id="step_add" name="step_add" style="width:90%;"/>
              </div>
              <div class="column-left" style="width:20%; padding-top:25px;">
                <input type="hidden" name="hosp" id="hosp" value="<? echo $hospid; ?>"/>
                <input type="submit" id="snd_upload" name="snd_upload" value="Submit Step" class='button'  />
              </div>
            </fieldset>
          </form>
          <form name="delete_form" method="post" id="delete_form">
            <fieldset style="height:100%;  margin-left:25px; margin-top:15px; background-color:#FFF;">
              <legend style="padding:2px;">List of Steps</legend>
              <h3>Drag and Drop to Change Step Order</h3>
              <input type="hidden" name="hosp" id="hosp" value="<? echo $hospid; ?>"/>
              <div id="step_list">
              <? echo $step_list ?>
              </div>
            </fieldset>
          </form>
        </div>
      </div>
    </div>
    <div class="clear"></div>
    <div id="footer">&#169; Copyright 2012  Inc. | <a href="#">Top</a></div>
  </div>
</div>
</body>

Okay, second edit, I think I'm starting to understand the problem here. Here is the php that is generating my list. And the element I'm clicking on is buried in the container. I don't wish to click the entire container, just the image inside. Is that possible? Thanks for all the advice so far. I'm learning....

function getSteps($dbh, $hospid)
{
    $sql1 = $dbh->prepare('
    SELECT COUNT(*) 
    FROM progress_steps
    WHERE hospital_id = :hospid
    ');
    $sql1->bindValue('hospid', $hospid);
    $sql1->execute();   
    $num_rows = $sql1->fetchcolumn();

    $sql = $dbh->prepare('
    SELECT * 
    FROM progress_steps
    WHERE hospital_id = :hospid
    ORDER BY step_number
    ');
    $sql->bindValue('hospid', $hospid);
    $sql->execute();
    if ($num_rows > 0) {
        $steps_table = '';
        $isOdd           = true;
        while (($row = $sql->fetch(PDO::FETCH_ASSOC)) !== false) {
            $steps_table .= "<div class='hover_hand' name='$row[step_id]' id='item_$row[step_id]'><div style='float:left' class='delete_it'><img src='../images/delete_icon.gif'></div> <div style='float:left' class='middle_text'>&nbsp;&nbsp;&nbsp;&nbsp;$row[step_name]</div><input type='hidden' name='itemid[]' value='$row[step_id]'/></div>";
        };
     } else {
        $steps_table = '';
            $steps_table .= "<div>You need to add steps.</div>";
    };
    return $steps_table;
}
Dev Newb
  • 565
  • 1
  • 6
  • 24
  • 1
    We need your HTML. The event is bound to a DOM element that is likely getting removed and readded without the bound event. – Cymen Dec 02 '12 at 17:56
  • I am using Firebug and it fails silently. Nothing pops up on the console – Dev Newb Dec 02 '12 at 18:06

3 Answers3

19

I am assuming (by your code) that the .delete_it item is inside the #step_list element.

So when you replace its html with the ajax results you remove the bound handlers as well..

You need to bind the handler to an element up in the DOM hierarchy that does not get removed, for example the #step_list itself..

So change the binding from

$(".delete_it").on('click',function() {

to

$("#step_list").on('click','.delete_it', function() {
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
3

It's hard to see from here. Would you mind sharing the HTML? Without knowing what the data.success contains doesn't make it easy also. Does the .html(data.success) affect the delete buttons in any way?

And are you sure you did the .live() right?

$('.delete_it').live("click",function(){

});

I might be able to help if you could provide more info.

Wap
  • 587
  • 1
  • 4
  • 14
  • Yeah I know. But I can never understand why they would deprecate .live(). It works, and I've never seen it fail. It's also pretty straightforward, just `$.live`, and that's it - just like `$.click()`. `$('.some class parent').on` with the optional param is just too damn long for my liking.haha but then again, you're also right. – Wap Dec 02 '12 at 18:17
  • I just read the docu, it has some drawbacks after all. But I'm stubborn, I'll stick with .live() all the way, until it bites back on me. :D – Wap Dec 02 '12 at 18:36
2

Events are bound to DOM nodes. If the DOM which you are binding to is removed the associated event will likely be removed too. You can fix this or you can make use of the "bubbling up" nature of DOM events. For example, say my HTML was this:

<div id="container">
  <div class="item delete_me_on_click"></div>
  <div class="item delete_me_on_click"></div>
  <div class="item delete_me_on_click"></div>
</div>

What I could do is bind to the #container or to document to listen to any click event and inspect the event's target to see if I want to take action. An example of that for the above HTML:

$('#container').on('click', function (event) {
    var target = $(event.target);
    if (target.hasClass('delete_me')) {
        target.remove();
    }            
});​

Which is the same as:

$('#container').on('click', '.delete_me', function (event) {
    $(event.target).remove();      
});​

Or I can even listen on the document level:

$(document).on('click', '.delete_me', function (event) {
    $(event.target).remove();      
});​

​Here is a working example: http://jsfiddle.net/Kcapv/

Note that event.stopPropagation() if used on a child node will stop the event bubbling up so if you try this approach you need to be careful to watch for use of stopPropagation.

Cymen
  • 14,079
  • 4
  • 52
  • 72
  • Is live deprecated? Should I use on or is live my only option here. Thx! – Dev Newb Dec 02 '12 at 18:08
  • Apparently it is according to the jQuery site. `on` should work as a replacement. – Cymen Dec 02 '12 at 18:10
  • Your post really helped me understand what is going on here. So I added my php code above. I have an image buried in the container that I want to fire the function. How can I get to that element without clicking on the entire container or running into the problem of only firing once? – Dev Newb Dec 02 '12 at 18:15
  • We don't have enough to answer your question that closely. Here is what you gave us in a jsfiddle: http://jsfiddle.net/2NGe7/ Note there is no element with the `delete_me` class so we can't reproduce your issue. – Cymen Dec 02 '12 at 18:22
  • +1 for all the help. You definitely helped me down the right path. Gaby was just able to bring it all together nicely. Thx for your advice! – Dev Newb Dec 02 '12 at 23:48
  • Using jQuery(document).on worked for me. Thank You – Shawn W Mar 04 '21 at 18:09