1

I want to display an alert message inside a loop fetching records from the database. The problem is, the popup only works for one item and the other item shows no popup.

What's going wrong?

PHP:

$query = "SELECT * FROM discount
          WHERE consecutivedays <=  DATEDIFF('$date2','$date1')
                AND idbeach = '$idbeach'
          ORDER BY consecutivedays desc
          LIMIT 1";

$results = mysqli_query($conn, $query);

while($row = $results->fetch_assoc()){

    $reserved= $row['discountperc'];

    if ($reserved=="yes") {

        $getbooking = new WA_MySQLi_RS("getbooking",$sis,1);

        $getbooking->setQuery("SELECT `name`,
                                      CONCAT(`datein`,' - ',`dateout`) AS dates,
                                      price,discount,comment
                               FROM booking
                               where idseatbeach = '$idseatbeach'
                               order by datein limit 1");

        $getbooking->execute();
        $name=$getbooking->getColumnVal("name");
        $dates=$getbooking->getColumnVal("dates");
        $price=$getbooking->getColumnVal("price");  
        $discount=$getbooking->getColumnVal("discount");    
        $comment=$getbooking->getColumnVal("comment");  
        $message = "Booked by: $name\n
                    Date range: $dates\n
                    Price :$price\n
                    Discount :$discount\n
                    Comment :$comment";

        ?>
        <div class="item" >
            <div class="popup" onclick="myFunction()">
                <span class="popuptext" id="myPopup"><?php echo $message;?></span>
                <img src="images/umbrelladisactive.png" width="35" height="35" 
                    alt="<?php echo $nameseat; ?> "/>
                <p style="margin-right: 0px; color: blue;">Currently Booked</p>
            </div>
        </div>
       <?php

   }
}

JavaScript:

var stile = "top=10, left=10, width=450, height=350,
             status=no, menubar=no, toolbar=no scrollbars=no";

function myFunction() {
  var popup = document.getElementById("myPopup");
  popup.classList.toggle("show");
}

CSS:

.item {
  width: 100px;
  text-align: center;
  display: block;
  background-color: transparent;
  border: 1px solid transparent;
  margin-right: 10px;
  margin-bottom: 1px;
  float: left;
}

#index-gallery {
  width: 50px;
}


/* Popup container */

.popup {
  position: relative;
  display: inline-block;
  cursor: pointer;
}


/* The actual popup (appears on top) */

.popup .popuptext {
  visibility: hidden;
  width: 160px;
  background-color: #555;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 8px 0;
  position: absolute;
  z-index: 1;
  bottom: 125%;
  left: 50%;
  margin-left: -80px;
}


/* Popup arrow */

.popup .popuptext::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: #555 transparent transparent transparent;
}


/* Toggle this class when clicking on the popup container (hide and show the popup) */

.popup .show {
  visibility: visible;
  -webkit-animation: fadeIn 1s;
  animation: fadeIn 1s
}


/* Add animation (fade in the popup) */

@-webkit-keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
showdev
  • 28,454
  • 37
  • 55
  • 73
Benson Kiprono
  • 129
  • 1
  • 1
  • 12

2 Answers2

3

An ID in HTML must be unique to the document, meaning that you can't repeat it in a loop. I recommend using a class instead, so it can be repeated.

You'll need to popup the element that's associated with (nested inside) whichever element was clicked. I recommend adding an event listener to each .popop that will fire a handler function upon click. The function should find the popup text within the clicked element by using querySelector and toggle its "show" class.

Here's an rudimentary example:

// define a function to show a popup's popuptext.
function popItUp() {
  this.querySelector('.popuptext').classList.toggle("show");
}

// define all popup elements.
let popups = document.querySelectorAll('.popup');

// add listener to each popup element, which binds handler function to click event.
popups.forEach(
  popup => popup.addEventListener('click', popItUp)
);

/*
// The arrow function above is equivalent to:
popups.forEach(function(popup){
  popup.addEventListener('click', popItUp);
});
*/
.item {
  width: 100px;
  text-align: center;
  display: block;
  background-color: transparent;
  border: 1px solid transparent;
  margin: 80px 0 0 50px;
  float: left;
}

.popup {
  position: relative;
  cursor: pointer;
}

.popup .popuptext {
  visibility: hidden;
  width: 160px;
  background-color: #555;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 8px 0;
  position: absolute;
  z-index: 1;
  bottom: 125%;
  left: 50%;
  margin-left: -80px;
}

.popup .popuptext::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: #555 transparent transparent transparent;
}

.popuptext.show {
  visibility: visible;
  -webkit-animation: fadeIn 1s;
  animation: fadeIn 1s
}

@-webkit-keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
<div class="item">
  <div class="popup">
    <span class="popuptext">Popup Message 1</span>
    <p>Currently Booked</p>
  </div>
</div>

<div class="item">
  <div class="popup">
    <span class="popuptext">Popup Message 2</span>
    <p>Currently Booked</p>
  </div>
</div>

<div class="item">
  <div class="popup">
    <span class="popuptext">Popup Message 3</span>
    <p>Currently Booked</p>
  </div>
</div>

There are likely some other layout issues with the CSS, but this might give you an idea of the JavaScript implementation.


For reference:

The id global attribute defines an identifier (ID) which must be unique in the whole document.

The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.

The EventTarget method addEventListener() sets up a function that will be called whenever the specified event is delivered to the target.

The querySelector() method of the Element interface returns the first element that is a descendant of the element on which it is invoked that matches the specified group of selectors.


Incidentally, I also notice that your query includes LIMIT 1, so the while loop will not iterate more than once. You may want to remove (or increase) that limit:

$query = "SELECT * FROM discount
          WHERE consecutivedays <=  DATEDIFF('$date2','$date1')
                AND idbeach = '$idbeach'
          ORDER BY consecutivedays desc;";
showdev
  • 28,454
  • 37
  • 55
  • 73
2

In HTML, the id attribute was designed to be unique in a document. document.getElementById() will always only return one element.

One way to solve your problem is to give each popup a unique id, and pass this id on to myFunction() so it knows which popup to display (I've removed all the in-between lines of code for the sake of brevity).

I assume your database records have some unique identifier along with name, dates, price, discount and column but since you haven't selected it in your current code I don't know for sure. If it doesn't, one alternative is to keep track of a unique counter yourself, such as $id here:

$id = 0;
while($row = $results->fetch_assoc()){
    $id++;

Then you can send that $id value on to your function and your popup id attribute to help Javascript figure out what you want:

<div class="popup" onclick="myFunction('myPopup<?php echo $id; ?>')">
    <span class="popuptext" id="myPopup<?php echo $id; ?>"><?php echo $message;?></span>

Your function should then be modified to understand that change:

function myFunction(elementId) {
    var popup = document.getElementById(elementId);
    popup.classList.toggle("show");
}
rickdenhaan
  • 10,857
  • 28
  • 37