0

I tried to google this question, and the answer to custom alert boxes in javascript is usually jquery dialog. And this works great with one query, but I have a huge table where 90% of the cells is supposed to be clickable to open up a small alert window with information.

I tried one Stack question (link under). But the same answer made a fault in the code.

So here is my sample code that "works" right now:

<table>
  <tr>
    <td>Manufacturer</td>
    <td>Product</td>
    <td>Price range 1</td>
    <td>Price range 1</td>
    <td>Price range 1</td>
  </tr>
  <tr>
    <td>Umbrella Company</td>
    <td>Vaccine</td>
    <td><div onclick="alert('1399')">1399</div></td>
    <td><div onclick="alert('4299')">4299</div></td>
    <td><div onclick="alert('5999')">5999</div></td>
  </tr>
</table>

This option works, and but is not working as custom. This other option, with custom code with jQuery works with one cell, and all the other cells just cries out the same statement.

Test the jsfiddle source under with both tables, one with alert() and one with jquery box.

Is it not possible to do it this way?

Source one: How to change the style of alert box? Source two: https://jsfiddle.net/olelasse/e6hk9340/

  • When you use a javascript dialog (maybe jqueryui/bootstrap/other), you can *reuse* the dialog. So you have a single dialog that you populate with your content (ideally, before showing it, but some people don't get that concept). You don't have 1 dialog per row. – freedomn-m Jan 31 '22 at 15:40
  • You would have one dialog box, as they said ^, it's not valid html to have multiple elements with the same id on the page. – Nikki9696 Jan 31 '22 at 15:41
  • In your code (fiddle) you have `
    ` but your functionAlert is expecting `function functionAlert(msg, myYes)` - you're not supplying a `msg` so it's always the same (original) message.
    – freedomn-m Jan 31 '22 at 15:41
  • As they said ^^ - `$("#confirm")` will always find the *first* div with id=confirm – freedomn-m Jan 31 '22 at 15:43
  • Updated fiddle (https://jsfiddle.net/2sbcn6u9/) - single "dialog" and removing onclick= – freedomn-m Jan 31 '22 at 15:48
  • If you have a huge table, then you probably shouldn't be coding the HTML by hand. You should start with the raw data then use JavaScript (or, perhaps, a library like React) to generate the UI dynamically. – JDB Jan 31 '22 at 15:55
  • Thank you all for commenting. I use PHP with MySQL to get the database information, and to create a loop for the Table. – Ole Lasse Bjellaas Feb 01 '22 at 15:27
  • I have another question. In the popup, how to I get the "close button" to be put on the bottom instead for straight after the text? – Ole Lasse Bjellaas Feb 01 '22 at 15:28

3 Answers3

2

You could avoid more duplication by using child functions or passing the element reference but this is the general idea. I'm not a huge fan of DOM refs because it's fragile. Move one element and everything goes to Hades in a handbasket.

function functionAlert(msg) {
   var confirmBox = $("#confirm");
   confirmBox.find(".message").text(msg);
   var myYes = confirmBox.find(".yes");
   myYes.on('click', function() {
      confirmBox.hide();
   });
   //myYes.click(myYes);
   confirmBox.show();
}
#confirm {
    display: none;
    background-color: #F3F5F6;
    color: #000000;
    border: 1px solid #aaa;
    position: fixed;
    width: 300px;
    height: 400px;
    left: 40%;
    top: 40%;
    box-sizing: border-box;
    text-align: center;
}
#confirm button {
    background-color: #FFFFFF;
    display: inline-block;
    border-radius: 12px;
    border: 4px solid #aaa;
    padding: 5px;
    text-align: center;
    width: 60px;
    cursor: pointer;
    bottom: 5px;
}
#confirm .message {
    padding: 5px;
    text-align: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
  <title>JS Alert Box</title>
</head>
<body>

<h2>
Table 1
</h2>
<h3>
Alert()
</h3>
<table border="1">
  <tr>
    <td>Manufacturer</td>
    <td>Product</td>
    <td>Price range 1</td>
    <td>Price range 2</td>
    <td>Price range 3</td>
  </tr>
  <tr>
    <td>Umbrella Company</td>
    <td>Vaccine</td>
    <td><div onclick="functionAlert('1399')">1399</div></td>
    <td><div onclick="functionAlert('4299')">4299</div></td>
    <td><div onclick="functionAlert('5999')">5999</div></td>
  </tr>
  <tr>
    <td>Umbrella Company</td>
    <td>Vaccine 2</td>
    <td><div onclick="functionAlert('1299')">1299</div></td>
    <td><div onclick="functionAlert('4199')">4199</div></td>
    <td><div onclick="functionAlert('5899')">5899</div></td>
  </tr>
  <tr>
    <td>Microhard</td>
    <td>PDA</td>
    <td><div onclick="functionAlert('999')">999</div></td>
    <td><div onclick="functionAlert('3599')">3599</div></td>
    <td><div onclick="functionAlert('6299')">6299</div></td>
  </tr>
</table>


 <div id="confirm">
 <div class="message">
 </div>
 <button class="yes">Close</button>
 </div>

</body>
</html>
Nikki9696
  • 6,260
  • 1
  • 28
  • 23
2

Don't write the HTML by hand. Generate it dynamically based on your data. You could use a library like React, or just use the DOM as I've demonstrated below.

This way, no matter how large your table is, you need only write the event handler logic once. There are additional ways you could simplify this code, but which you choose will depend on your experience and goals.

// All your data are belong to this array
const data = [
  ["Umbrella Company", "Vaccine", 1399, 4299, 5999],
  ["Soylent Corporation", "Soylent Green", 299, 399, 599],
  ["Omni Consumer Products", "ED-209", 19990, 39990, 78990],
  ["Tyrell Corporation", "Nexus-6", 27990, 31990, 59990],
];

const table = document.getElementById("products");

for (const row of data) {
  const tr = document.createElement("tr");
  
  const manTD = document.createElement("td");
  manTD.innerText = row[0];
  tr.appendChild(manTD);

  const prodTD = document.createElement("td");
  prodTD.innerText = row[1];
  tr.appendChild(prodTD);
  
  const range1TD = document.createElement("td");
  range1TD.innerText = row[2];
  range1TD.addEventListener("click", function() {
    alert(row[2]);
  });
  tr.appendChild(range1TD);
  
  const range2TD = document.createElement("td");
  range2TD.innerText = row[3];
  range2TD.addEventListener("click", function() {
    alert(row[3]);
  });
  tr.appendChild(range2TD);
  
  const range3TD = document.createElement("td");
  range3TD.innerText = row[4];
  range3TD.addEventListener("click", function() {
    alert(row[4]);
  });
  tr.appendChild(range3TD);

  table.appendChild(tr)
}
<table id="products">
  <tr>
    <th>Manufacturer</th>
    <th>Product</th>
    <th>Price range 1</th>
    <th>Price range 1</th>
    <th>Price range 1</th>
  </tr>
</table>
JDB
  • 25,172
  • 5
  • 72
  • 123
  • Thank you for your tip! The HTML I put in my question, was sample data. But my correct data is gathered from MySQL database with PHP, so JS was just for the alert box – Ole Lasse Bjellaas Feb 01 '22 at 15:24
2

Whenever possible try and keep your code DRY, below I've modified your code to do the following->

  1. Used a delegated event handler on the table. This means you only need one event to handle all the TD's, and better still if a TD was added dynamically later it would work with the added lines.

  2. Used an array to store the data, we can then use this to render the table lines.

  3. Used the .dataset property to store the type of data stored in the TD, I'm only using this to prevent the dialog showing if you don't click a TD with numbers in, but I could have used a class, or even parsed the .innerText

const data = [
  ["Umbrella Company", "Vaccine", 1399, 4299, 5999],
  ["Umbrella Company", "Vaccine2", 1299, 4199, 5899],
  ["Microhard", "PDA", 999, 3599, 6299]
];

const table =
  document.querySelector('table');
const confirmBox =
  document.querySelector('#confirm');
const confirmBoxMsg =
  confirmBox.querySelector('.message');
const confirmBoxYes =
  confirmBox.querySelector('.yes');

function fillTable() {
  for (const d of data) {
    const tr = document.createElement('tr');
    for (const v of d) {
      const td = document.createElement('td');
      td.dataset.type = typeof v;
      td.innerText = v;
      tr.appendChild(td);
    }
    table.appendChild(tr);
  }
}

table.addEventListener('click', ev => {
  const td = ev.target.closest('td');
  if (!td) return; //did with click a TD?
  if (td.dataset.type !== 'number') return; 
  confirmBoxMsg.innerText = td.innerText;
  confirmBox.style.display = 'block';
});

confirmBoxYes.addEventListener('click', ev => {
  confirmBox.style.display = 'none';
});

fillTable();
#confirm {
    display: none;
    background-color: #F3F5F6;
    color: #000000;
    border: 1px solid #aaa;
    position: fixed;
    width: 300px;
    height: 400px;
    left: 40%;
    top: 40%;
    box-sizing: border-box;
    text-align: center;
}
#confirm button {
    background-color: #FFFFFF;
    display: inline-block;
    border-radius: 12px;
    border: 4px solid #aaa;
    padding: 5px;
    text-align: center;
    width: 60px;
    cursor: pointer;
    bottom: 5px;
}
#confirm .message {
    padding: 5px;
    text-align: left;
}
<html>
<head>
  <title>JS Alert Box</title>
</head>
<body>

<h2>
Table 1
</h2>
<h3>
Alert()
</h3>
<table border="1">
  <tr>
    <td>Manufacturer</td>
    <td>Product</td>
    <td>Price range 1</td>
    <td>Price range 2</td>
    <td>Price range 3</td>
  </tr>
</table>


 <div id="confirm">
 <div class="message">
 </div>
 <button class="yes">Close</button>
 </div>

</body>
</html>
Keith
  • 22,005
  • 2
  • 27
  • 44