DevOpsSauce
DevOpsSauce

Reputation: 1387

How to use jQuery .remove() on div created using while/fetch in PHP?

I have a Bootstrap modal that displays both Read and Unread messages from a database:

Message Modal

It shows a notification badge (see top) if there are unread messages. I've added a delete button, but can't figure out how to remove the entire div that contains that specific button, including the hr tag. The problem is that it only deletes the second div and hr tag you see there, but not the first. I even have an alert set up and it shows me the correct div id for the second. The first does nothing. This is what I tried. It's the code for the entire modal div:

<div id="messages_modal" class="modal fade" role="dialog">
<div class="modal-dialog modal-messages-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <h4 class="modal-title" id="modal_label">Messages
                <button class="close" data-dismiss="modal">&times;</button>
            </h4>
        </div>
        <div class="modal-body">
            <?php
            $subject = "";
            $query = "SELECT id FROM `users` WHERE username=?";
            if (!$stmt = $connection->prepare($query)) {
                echo $stmt->error;
            } else {
                if (!$stmt->bind_param('s', $username)) {
                    echo $stmt->error;
                } else {
                    $stmt->execute();
                    $stmt->bind_result($recip_id);
                    $stmt->fetch();
                    $stmt->close();
                }
            }
            $query = "SELECT username, avatar, conversation_id, conversation_subject, time, msg_seen FROM `users` INNER JOIN `conversation` ON `users`.id = `conversation`.user_1
                          WHERE user_2 = ? ORDER BY time DESC";
            if (!$stmt = $connection->prepare($query)) {
                echo $stmt->error;
            } else {
                if (!$stmt->bind_param('i', $recip_id)) {
                    echo $stmt->error;
                } else {
                    $stmt->execute();
                    $stmt->bind_result($sender_name, $avatar, $msg_id, $subject, $timestamp, $msg_seen);
                    while ($stmt->fetch()) {
                        $div_count++;
                        if ($msg_seen == 0) {
                            $notification_count++;
                        }
                        $subject = (strlen($subject) > 16) ? substr($subject, 0, 14) . '...' : $subject;
                        ?>

STARTING POINT OF WHERE I WANT TO DELETE

                        <div id="msg_content_<?php echo $div_count;?>" class="msg-content">
                            <div class="avatar-container">
                                <a href="../pages/messages.php?id=<?php echo $msg_id; ?>" class="lighten"><img
                                            src="<?php echo $avatar; ?>" class="msg-avatar"></a>
                                <div class="text-container">
                                    <span class="show-sender"><?php echo $sender_name; ?></span>
                                    <span class="show-msg-status"><?php
                                        if ($msg_seen == 0) {
                                            echo "Unread";
                                        } else {
                                            echo "Read";
                                        }
                                        ?></span>
                                    <br/>
                                    <span class="show-msg"> Subject: <em><?php echo $subject; ?></em></span>
                                    <button id="msg_delete_btn_<?php echo $div_count;?>" class="delete-btn">delete</button>
                                    <br/>
                                    <span class="show-timestamp"><?php echo date('D, F jS, Y h:i A', strtotime($timestamp)); ?></span>
                                </div>
                            </div>
                        </div>
                        <hr id="<?php echo $div_count;?>">

ENDING POINT OF WHERE I WANT TO DELETE

                     <?php
                    }
                    $stmt->close();
                }
            }
            ?>
        </div>
    </div>
</div>

Screenshot of what I need deleted:

Div needing deleted

Here is my jQuery. The alert shows me "msg_delete_btn_2", which is the correct dynamically generated id, but it this is only working for 2nd message.

$(document).ready(function () {
    $('#msg_delete_btn_<?php echo $div_count;?>').click(function() {

        $('#msg_content_<?php echo $div_count;?>').remove(); //<-- REMOVES DIV
        $('#<?php echo $div_count;?>').remove(); //<-- REMOVES <hr> TAG
        alert(this.id); //<-- SHOWS ME "msg_delete_btn_2" for 2nd div, which is correct. First div does nothing.

    });
});

So, how can I access any div via the delete button? I tried giving the button and the div their own id by creating a count variable to no avail.

Upvotes: 0

Views: 164

Answers (3)

u_mulder
u_mulder

Reputation: 54831

Your problem is that after all iterations of a while, variable $div_count holds the last value.

So, if you have two rows, your js code becomes:

$('#msg_delete_btn_2').click(/* other code */);

So your code knows nothing about other msg_delete_btn_ buttons.

The simple solution is to use class instead, you already have it delete-btn, or add another class:

$('.delete-btn').click(function() {
    // remove following hr element which is after closest `div.msg-content` in which this button is
    $( this ).closest( ".msg-content" ).next( "hr" ).remove();        
    // remove closest `div.msg-content` in which this button is
    $( this ).closest( ".msg-content" ).remove();   // remove 

    // first `hr` then `div` because if you first
    // delete `div` then `hr` WILL NOT BE FOUND
});

More sopisticated solution (if your markup will change) can be to store current $div_count in a data attribute of a button and generate proper ids using it. Something like:

<button data-id="<?php echo $div_count;?>" class="delete-btn">delete</button>

$('.delete-btn').click(function() {
    var itemId = $( this ).data( "id" );
    $( "msg_content_" + itemId ).remove();
    // more codes

Upvotes: 1

Nik Lakhani
Nik Lakhani

Reputation: 217

Try this one, It should work!

$(document).ready(function() {
    $('.delete-btn').on('click', function() {
        $(this).closest('.msg-content').next('hr').remove(); //<-- REMOVES <hr> TAG
        $(this).closest('.msg-content').remove(); //<-- REMOVES DIV
    });
})();

Upvotes: 1

Ikhlak S.
Ikhlak S.

Reputation: 9034

Use class and remove the unnecessary id tags.

You can use $(this) to target the current element and the closest .msg-content class.

$(document).on('click', '.delete-btn', function(){
  $(this).closest('.msg-content').remove();
});

Another improvement:

No need to have hr tags instead give the them a style of border-bottom:1px solid #d3d3d3;

.msg-content{border:1px solid #d3d3d3;}
.msg-content:last-child{border:1px solid transparent;} /* Hide border of last element */ 

Upvotes: 1

Related Questions