Reputation: 25
and thank you for your time. Since I've added two+ buttons (run the code and press the "add table" button), all it does is add two new rows to the first table, and the subsequent buttons don't work. I've tried calling the classes, using the loop, and putting the code where it should be, but it still refuses. Here is my code:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="WELPPproto.css">
</head>
<body>
<h1 style="font-family:verdana">Word List</h1>
<table id="list">
<tr>
<th scope="col">Word</th>
<th scope="col">English</th>
<th scope="col">Pronunciation</th>
<th scope="col"><button class="deletethismaybe" id="deletethismaybe" type="button" title="delete this table">X</button></th>
</tr>
<tfoot>
<tr>
<div class="boxy_gril">
<td><input type="text" id="w" class="w" required /></td>
<td><input type="text" id="m" class="m" required /></td>
<td><input type="text" id="p" class="p" /></td>
</div>
</tr>
<tr>
<td colspan="3"><div class="button_boi"><button type="button" class="button_boi" id="add">Enter</button>
</div></td>
</tr>
</tfoot>
</table>
<div id="ntable" class="ntable" >
<section>
</section>
</div>
<br>
<br>
<button class="button_gril" id="addtable">Add Table</button>
<script>
document.getElementById("addtable").onclick = function() {
let puttable = document.getElementById("ntable");
let section = puttable.querySelector('section');
let tableHTML = '<br><br>' + '<table id="list">' + '<tr>' +
'<th scope="col">' + 'Word' + '</td>' +
'<th scope="col">' + 'English' + '</th>' +
'<th scope="col">' + 'Pronunciation' + '</th>' + '<th><button class="deletethismaybe" id="deletethismaybe" type="button" title="delete this table">X</button></th>' +
'</tr>' +
'<tfoot><tr><div class="boxy_gril">' +
'<td><input type="text" id="w" class="w" required /></td>'+
'<td><input type="text" id="m" class="m" required />' +
'</td><td><input type="text" id="p" class="p" /></td>' +
'</div></tr>' + '<tr>' + '<td colspan="3">' + '<div class="button_boi">' + '<button type="button" class="button_boi" id="add">Enter</button>' + '</div>' + '</td>'+ '</tr>' + '</tfoot>' + '</table>';
section.insertAdjacentHTML('beforebegin', tableHTML);
}
document.addEventListener('click', (e) => {
let thatTarget = e.target;
let thatBtn = thatTarget.closest('.deletethismaybe');
if (thatBtn) {
e.preventDefault();
thatTarget.closest('table').remove();
thatTarget.closest('button').remove();
}
})
var asdf = document.getElementsByClassName("button_boi");
for (var i = 0; i < asdf.length; i++) {
asdf[i].onclick = function() {
let listTable = document.getElementById("list");
let tfoot = listTable.querySelector('tfoot');
let wordValue = document.getElementById("w").value;
let engValue = document.getElementById("m").value;
let pronunValue = document.getElementById("p").value;
let trHTML = '<tr>' +
'<td>' + wordValue + '</td>' +
'<td>' + engValue + '</td>' +
'<td>' + pronunValue + '</td>' + '<td><button class="deletethis" type="button" title="delete this row">X</button></td>' +
'</tr>';
tfoot.closest('tfoot').insertAdjacentHTML('beforebegin', trHTML);
}
}
document.addEventListener('click', (e) => {
let thisTarget = e.target;
let thisBtn = thisTarget.closest('.deletethis');
if (thisBtn) {
e.preventDefault();
thisTarget.closest('tr').remove();
}
})
document.getElementsByClassName('.deletethismaybe').onclick = function() {
let thatTarget = e.target;
let thatBtn = thatTarget.closest('.deletethismaybe')
if (thatBtn) {
e.preventDefault();
thatTarget.closest('table').remove();
}}
</script>
</body>
</html>
Upvotes: 0
Views: 1219
Reputation: 4755
I think you have to try to understand about JavaScript Event delegation. There are a lot of tutorials about this for example 1, 2, 3, and a lot more on Google.
If you understand how it works, it will be easy and very helpful for you that you don't have to create or call many many event listeners.
Let see my example.
let addNewBtn = document.getElementById('add-new-btn');
addNewBtn.onclick = function() {
let newBtnHTML = '<button class="addtext" type="button">Add some text</button>';
document.getElementById('new-button-placeholder').insertAdjacentHTML('beforeend', newBtnHTML);
};
// below is how event delegation works.
// start with listen for click event on root element (`document`)
document.addEventListener('click', (e) => {
let thisTarget = e.target;
// the code above is to get `.target` property of clicked element for use later.
let thisBtn = thisTarget.closest('.addtext');
// the code above is to get closest button that has `addtext` in the class value. If this button is not exists then it will not go inside the `if` below.
if (thisBtn) {
// if this button exists.
e.preventDefault();// this is for prevent default action in case of form submit. It is no need in this example but just in case you may have to use it later.
// now add some text to `.debug` HTML element.
let someText = 'Hello world';
document.querySelector('.debug').insertAdjacentHTML('beforeend', '<p>' + someText + '</p>');
}
// if button is not exists, it will be ignore and has nothing to work here anymore.
});
.debug {
border: 2px dashed #ccc;
margin-bottom: 20px;
padding: 10px;
}
<div class="debug"></div>
<button class="addtext" type="button">Add some text</button>
<button id="add-new-btn" type="button">Add new button that will be clicked and add some text</button>
<hr>
<div id="new-button-placeholder"></div>
Please read the code comment above because I was described everything step by step.
The example code above will work when you click on Add some text and Add new button that will be clicked and add some text buttons. The newly added buttons will be work the same way as existing button without to call or add any new event listener.
This is how Event delegation works.
Now with your work.
id
. The delete button with id="deletethismaybe"
or anything with id=".."
that has the same value when you add should be omitted. Use class=".."
instead. This is for valid HTML.deletethismaybe
, or thatBtn
, etc because you will confuse yourself in the future.td
, or th
must be inside tr
only NOT inside div
. So, <div class="boxy_gril">
is invalid HTML!document.getElementById("addtable").onclick = function() {
let puttable = document.getElementById("ntable");
let section = puttable.querySelector('section');
let tableHTML = '<br><br>' + '<table class="list">' + '<tr>' +
'<th scope="col">' + 'Word' + '</td>' +
'<th scope="col">' + 'English' + '</th>' +
'<th scope="col">' + 'Pronunciation' + '</th>' + '<th><button class="delete-table" type="button" title="delete this table">X</button></th>' +
'</tr>' +
'<tfoot><tr>' +
'<td><input type="text" class="w" required /></td>' +
'<td><input type="text" class="m" required />' +
'</td><td><input type="text" class="p" /></td>' +
'</tr>' + '<tr>' + '<td colspan="3">' + '<div class="button_boi">' + '<button type="button" class="button_boi addrow">Enter</button>' + '</div>' + '</td>' + '</tr>' + '</tfoot>' + '</table>';
section.insertAdjacentHTML('beforebegin', tableHTML);
}
// listen click event from root element (`document`).
document.addEventListener('click', (e) => {
let thisTarget = e.target;
// work with delete table button.
let deleteTableBtn = thisTarget.closest('.delete-table');
if (deleteTableBtn) {
// if delete button exists.
e.preventDefault();
thisTarget.closest('table').remove();
}
// end
// work with add row button.
let addRowBtn = thisTarget.closest('.addrow');
if (addRowBtn) {
// if add row button exists.
e.preventDefault();
// get closest table element for use later.
let thisTable = addRowBtn.closest('table');
// get input values that is under this table where add button was clicked.
let wordValue = thisTable.querySelector('.w').value;
let engValue = thisTable.querySelector('.m').value;
let pronunValue = thisTable.querySelector('.p').value;
// generate new table row (`tr`)
let trHTML = '<tr>' +
'<td>' + wordValue + '</td>' +
'<td>' + engValue + '</td>' +
'<td>' + pronunValue + '</td>' + '<td><button class="delete-row" type="button" title="delete this row">X</button></td>' +
'</tr>';
thisTable.querySelector('tfoot').insertAdjacentHTML('beforebegin', trHTML);
}
// end
// work with delete row button.
let deleteRowBtn = thisTarget.closest('.delete-row');
if (deleteRowBtn) {
// if delete row button exists.
e.preventDefault();
thisTarget.closest('tr').remove();
}
// end
})
<h1 style="font-family:verdana">Word List</h1>
<table class="list">
<tr>
<th scope="col">Word</th>
<th scope="col">English</th>
<th scope="col">Pronunciation</th>
<th scope="col"><button class="delete-table" type="button" title="delete this table">X</button></th>
</tr>
<tfoot>
<tr>
<td><input type="text" id="w" class="w" required /></td>
<td><input type="text" id="m" class="m" required /></td>
<td><input type="text" id="p" class="p" /></td>
</tr>
<tr>
<td colspan="3">
<div class="button_boi"><button type="button" class="button_boi addrow">Enter</button>
</div>
</td>
</tr>
</tfoot>
</table>
<div id="ntable" class="ntable">
<section>
</section>
</div>
<br>
<br>
<button class="button_gril" id="addtable">Add Table</button>
From the code above you will see that I use only one event listener and detect that what button does it come form and work with it inside if
condition if button exists.
See it in jsfiddle.
Again: Please try to understand about Event delegation as I described from the first because I believe that it will be useful for you.
Upvotes: 0
Reputation: 765
That's because the event listeners you created only listens to those that have already been created initially. When new elements get appended in the DOM, you will have to add another event listeners to them as well.
Here's an example on how to do it:
<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.0" />
<title>Document</title>
</head>
<body>
<ul id="lists">
<li class="list-item">
<div>List #1</div>
<button class="btn-delete">Delete</button>
</li>
</ul>
<div>
<button id="btn-add">Add new item to list</button>
</div>
<script>
const listsEl = document.getElementById('lists');
// Delete button elements
let deleteBtnEls = document.querySelectorAll('.btn-delete');
const deleteBtnOnClick = (e) => {
const listItemEl = e.target.closest('.list-item');
listsEl.removeChild(listItemEl);
};
const removeEventListeners = () => {
deleteBtnEls.forEach((deleteBtnEl) => {
deleteBtnEl.removeEventListener('click', deleteBtnOnClick);
});
};
const updateEventListeners = () => {
// remove existing event listeners to prevent duplicate event listeners
removeEventListeners();
// get the updated list of delete button elements
deleteBtnEls = document.querySelectorAll('.btn-delete');
deleteBtnEls.forEach((deleteBtnEl) => {
deleteBtnEl.addEventListener('click', deleteBtnOnClick);
});
};
// Add new item button element
const addBtnEl = document.getElementById('btn-add');
addBtnEl.addEventListener('click', () => {
const newListItemEl = document.createElement('li');
newListItemEl.className = 'list-item';
newListItemEl.innerHTML = `
<div>List #${listsEl.childElementCount + 1}</div>
<button class="btn-delete">Delete</button>
`;
listsEl.appendChild(newListItemEl);
updateEventListeners();
});
// Initial call
updateEventListeners();
</script>
</body>
</html>
Upvotes: 1