2

I am dynamically creating html divs with an additional div which acts like a button (OpenMessageButton).

These divs are templates for messages and as are populated with different information based on a query but the html elements themselves are identical including the html classes which they use.

I want to display a slide down drawer effect for reading the message, but I have an issue with trying to trigger this effect as it triggers for all messages as opposed to the specific message I clicked the button in

I have searched for this question and the nearest I have found is this: jQuery $(".class").click(); - multiple elements, click event once

Code For divs

    <?php
          while($row = mysql_fetch_assoc($myMessages))
          {
          ?>

    <!-- First Div to be clicked -->
    <div class="OpenMessageButton">Click to Open/Close</div>

    <!-- Div to be shown when OpenMessageButton is clicked --> 
    <div class="panel panel-default messageContent" style="display:none;">
      <div class="panel-body">
        <h4 class="card-title">Message: </h4>
        <p class="card-text">Text.</p>
        <div class="OpenMessageButton">Open</div>
      </div>

    </div>

    <!-- Second Div to be clicked -->
    <div class="OpenMessageButton">Click to Open/Close</div>

    <!-- Div to be shown when OpenMessageButton is clicked -->
    <div class="panel panel-default messageContent" style="display:none;">
      <div class="panel-body">
        <h4 class="card-title">Message: </h4>
        <p class="card-text">Text.</p>
        <div class="OpenMessageButton">Open</div>
      </div>

    </div>

    <!-- Third Div to be clicked -->
    <div class="OpenMessageButton">Click to Open/Close</div>

    <!-- Div to be shown when OpenMessageButton is clicked -->
    <div class="panel panel-default messageContent" style="display:none;">
      <div class="panel-body">
        <h4 class="card-title">Message: </h4>
        <p class="card-text">Text.</p>
        <div class="OpenMessageButton">Open</div>
      </div>

</div>

The jQuery I am using to trigger is as follows:

$('.OpenMessageButton').on('click',function(){
      var link = $(this);      
      $('.panel.panel-default.messageContent').slideToggle('fast', function(){
        if ($(this).is(':visible')){
          link.text('Close');                    
        }else{
          link.text('Open');                    
        }
      });           
  });

The identifier for the button is OpenMessageButton which gets triggered when any one of the buttons is clicked yet the jQuery triggers all the divs which is not desired. I would like to figure out a way for when a button is clicked only that div related to that top div is shown.

See the Fiddle https://jsfiddle.net/rasa56j8/

-- UPDATE -- (I am struggling to get the suggested answers working so I thought I would post the full page for completeness)

<?php
require 'core/database/db_connect.php'; //DB Connection
require 'get_inbox_messages.php'; //Retrieves inbox msgs from db
require 'getprofile.php'; //Get Profile
?>

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-   scale=1">

        <title>BlackBook Profile</title>

        <!-- Bootstrap core CSS -->
        <link href="css/bootstrap.min.css" rel="stylesheet">
        <!-- Bootstrap theme -->
        <link href="css/bootstrap-theme.min.css" rel="stylesheet">
        <!-- Custom styles for this template -->
        <link href="css/signin.css" rel="stylesheet">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
      </head>

      <body role="document">

        <!-- Fixed navbar -->
        <nav class="navbar navbar-inverse navbar-fixed-top">
          <div class="container">
            <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              <a class="navbar-brand image" href="profile.php" ><img src="Graphics/topLogo3.png" alt="BookLove"></a>
              <a class="navbar-brand" href="#">LoveBook</a>
            </div>
           <div id="navbar" class="navbar-collapse collapse">
              <ul class="nav navbar-nav navbar-right">
                <li ><a href="profile.php">Profile</a></li>

                <li class="dropdown">
                <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Messages<span class="caret"></span></a>
                <ul class="dropdown-menu">
                <li><a href="message_inbox.php">Inbox</a></li>
                <li><a href="sent_messages.php">Sent Messages</a></li>            
                </ul>
                </li>

                <li role="presentation"><a href="matched_users_output.php">Matches 
                <?php 
                $result = mysql_fetch_array($NewMatchesResult);

                if ($result[0][0] != 0) {
                  echo '<span class=badge>';
                  echo $result[0][0];    
                  echo '</span>';
                }                                                        
                ?>
                </a></li>
                <li ><a href="browse.php">Browse</a></li>

                <li class="dropdown">
                  <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Options <span class="caret"></span></a>
                  <ul class="dropdown-menu">
                    <li><a href="changeprofilepic.html">Change Profile Pic </a></li>
                    <li><a href="payment.html">Payment Details</a></li>
                    <li><a href="populate_questions.php">Update Interests</a></li>
                    <li role="separator" class="divider"></li>
                    <li class="dropdown-header"></li>
                    <li><a href="cancel.html">Cancel Account</a></li>
                    <li><a href="signin.html">Logout</a></li>
                  </ul>
                </li>
              </ul>
            </div><!--/.nav-collapse -->
          </div>
        </nav>

        <div class="container theme-showcase" role="main">

          <div class="page-header" >
            <h1>
            <?php  $username = mysql_fetch_assoc($usernameResult);
            echo $username['username']. '\'s';?> Inbox</h1>                            
          </div>


          <?php
          while($row = mysql_fetch_assoc($myMessages))
          {      
            $subject = $row['subject'];
            $content = $row['content'];
            $recipientID = $row['recipient_id'];
            ?>

            <!-- Message Div -->
          <div class="row">
          <div class="col-md-12"><div class="card card-block messages">      
          <h4 class="card-title"><em>Subject: <?php echo $subject; ?></em></h4>
          <h4 class="card-title">From:      
          <?php
          echo $row['member_id'];       
          $from = mysql_query("SELECT username FROM members WHERE member_id = '$recipientID'");
          while($row = mysql_fetch_assoc($from)) {          
              echo $row['username']; }
          ?></h4>
          <!-- <p class="card-text">MESSAGE CONTENT.</p> -->
          <div class="OpenMessageButton">Open</div>
          <div class="ReplyMessageButton">Reply</div>
          <div class="MarkAsReadButton">Mark as Read</div>
          <div class="DeleteMessageButton">Delete</div>  
        </div>
        </div>
        </div>
        <!-- Opened Message Div  -->
        <div class="panel panel-default messageContent">
      <div class="panel-body">
        <h4 class="card-title">Message: </h4>
        <p class="card-text"><?php echo $content; ?>.</p>
      </div>
    </div>
      <?php
          }
        ?>

      <script>

      $('.OpenMessageButton').on('click',function(){
          var link = $(this);      
          $('.messageContent').slideToggle('fast', function(){
            if ($(this).is(':visible')){
              link.text('Close');                    
            }else{
              link.text('Open');                    
            }
          });           
      });


      //   $('.OpenMessageButton').on('click',function(){
      //     var link = $(this);      
      //     $('.panel').slideToggle('fast', function(){
      //       if ($(this).is(':visible')){
      //         link.text('Close');                    
      //       }else{
      //         link.text('Open');                    
      //       }
      //     });           
      // });
      </script>


        <!-- Bootstrap core JavaScript
        ================================================== -->
        <!-- Placed at the end of the document so the pages load faster -->
        <!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> -->
        <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
        <script src="js/bootstrap.min.js"></script>
        <script src="js/docs.min.js"></script>
      </body>
    </html>
Community
  • 1
  • 1
roryjmaher
  • 63
  • 5
  • I will post the main code block just for completeness, for some reason I cannot get the suggested answers working so far – roryjmaher Apr 17 '16 at 00:01

4 Answers4

2

This line is the problem:

  $('.panel.panel-default.messageContent') ....

You match here all massages. You have to find a way to match only the message that belongs to clicked button.

One of solutions could be to wrap every button+message with additional container like:

<div class="MessageContainer"> <!--added this container -->
    <!-- First Div to be clicked -->
    <div class="OpenMessageButton">Click to Open/Close</div>

    <!-- Div to be shown when OpenMessageButton is clicked --> 
    <div class="panel panel-default messageContent" style="display:none;">
      <div class="panel-body">
        <h4 class="card-title">Message: </h4>
        <p class="card-text">Text.</p>
        <div class="OpenMessageButton">Open</div>
      </div>

    </div>
</div>

And then you can change this:

$('.panel.panel-default.messageContent')

to this:

link.closest('.MessageContainer').find('.panel.panel-default.messageContent')

Here's working example

https://jsfiddle.net/rasa56j8/2/

Jakub Matczak
  • 15,341
  • 5
  • 46
  • 64
0

You need to associate each open/close link with its respective div somehow. Here is one way to do it, using div ids and jQuery's .data()

<!-- Third Div to be clicked -->
<div class="OpenMessageButton" data-control="message3">Click to Open/Close</div>

<!-- Div to be shown when OpenMessageButton is clicked -->
<div id="message3" class="panel panel-default messageContent" style="display:none;">
  <div class="panel-body">
    <h4 class="card-title">Message: </h4>
    <p class="card-text">Text.</p>
    <div class="OpenMessageButton">Open</div>
  </div>

Then in the JS:

$(document.body).on('click', '.OpenMessageButton', function(){
      var link = $(this);  
      var div_id = $(this).data('control');      
      $(div_id).slideToggle('fast', function(){
        if ($(this).is(':visible')){
          link.text('Close');                    
        }else{
          link.text('Open');                    
        }
      });           
  });
larsAnders
  • 3,813
  • 1
  • 15
  • 19
  • Would this still have a similar issue as what I was having before as data-control="message3" would be essentially identical for all divs created dynamically? – roryjmaher Apr 17 '16 at 00:15
  • 1
    Right, so whether you create the divs in a php while loop, or dynamically, they will all need a unique id for this to work. Also, I'm going to re-write the listener to handle dynamically added divs. – larsAnders Apr 17 '16 at 00:27
0

You should use the jQuery method next() instead, because it selects only the next element (in your case the div with class 'panel') instead of all your panel's.

So change your js code to:

$('.OpenMessageButton').click(function(){
      var link = $(this);      
      link.next().slideToggle('fast', function(){
        if ($(this).is(':visible')){
          link.text('Close');                    
        }else{
          link.text('Open');                    
        }
      });           
  });
bang
  • 4,982
  • 1
  • 24
  • 28
  • I'm not sure .next() would work for me as the targeted div is not technically the next div in the list but maybe the third or fourth div after .OpenMessageButton – roryjmaher Apr 17 '16 at 00:17
0

Since you're trying to toggle for the jQuery event source, you should to change:

$('.panel.panel-default.messageContent').slideToggle('fast', function(){

to

$( this ).slideToggle('fast', function(){

The jQuery doc says:

When jQuery calls a handler, the this keyword is a reference to the element where the event is being delivered; for directly bound events this is the element where the event was attached and for delegated events this is an element matching selector. (Note that this may not be equal to event.target if the event has bubbled from a descendant element.) To create a jQuery object from the element so that it can be used with jQuery methods, use $( this ).

I took a different perspective on how to implement the function:

$('.OpenMessageButton').on('click', function() {
  var link = $(this);

  // If sub-text is already visible
  if (link.next().is(':visible')) {
    // Reset the link text
    link.text('Open');
    // Hide the sub-text
    link.next().hide();
  } else {
    // Reset the link text
    link.text('Close');
    // Show the sub-text
    link.next().slideToggle('fast', function(){ } );
  }
});
user212514
  • 3,110
  • 1
  • 15
  • 11
  • I felt this should work too as it makes sense however it does not in my example. I updated the code above just to give more context. – roryjmaher Apr 17 '16 at 00:09