Add onclick to a button with java script [duplicate] - javascript

This question already has an answer here:
addEventListener in Javascript triggers the click event automatically
(1 answer)
Closed 1 year ago.
I am creating a list of buttons inside a table, like this:
let tbody = document.createElement("tbody");
tbody.className = "table-responsive";
let id = 0;
for (let c of rows) {
let tr = document.createElement("tr");
tr.className = "table";
for (const v of c) {
let td = document.createElement("td");
td.className = "table";
let txt = document.createTextNode(v);
td.appendChild(txt);
tr.appendChild(td);
}
id++;
let button = document.createElement("button");
button.innerHTML = "ACTUALIZAR DATOS";
button.className = "btn btn-outline-primary";
button.id = id++;
button.onclick = upgradePet();
tr.appendChild(button);
tbody.appendChild(tr);
}
the table shows correctly, but when i try to add the .onclick, but when the table load, it call immediately the function upgradePet() without me clicking it.
i try doing:
button.addEventListener("click", upgradePet());
button.onclick = upgradePet();
but both call the function when the table finish render.

Remove the parentesis from your upgradePet as that represents a function call (meaning you are not just defining the function on the click event, but you're calling it straight away).
So this works fine,
button.onclick = upgradePet;
In case you will ever need to define functions with parameters, you can write them as followed,
button.onclick = () => upgradePet(param);

Remove the parentesis.
addEventListener
onclick
button.addEventListener("click", upgradePet);
button.onclick = upgradePet;

Two things to fix:
Add function objects as event listeners, not the value returned from calling a handler function. The return value is often undefined or, more rarely, a boolean value:
element.addEventListener( eventName, handler); ✔️
element.addEventListener( eventName, handler()); ❌
Do not append a <button> element to a table row - they are not valid child elements of a <tr> element. Create an extra td element, put the button element inside it and append the table data element created to the table row.

Related

how to remove selected list element, instead of removing only top li tag

I'm trying to remove specific li elements, based off of which one has the x button clicked. Currently I'm having an error
"bZMQWNZvyQeA:42 Uncaught TypeError: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'."
I am aware that this could mean that the paramater is null, but this dosn't make any sense to me. Chrome dev tools show that the onClick attribute is correctly exectuing removeItem, and passing in the idName as a parameter. How is this not working?
var note = 0;
function saveInfo() {
var idName = "note" + note;
//assign text from input box to var text, and store in local storage
var input = document.getElementById('input').value;
var text = localStorage.setItem(note, input);
var list = document.createElement("li");
var node = document.createTextNode(input);
var removeBtn = document.createElement("button");
list.setAttribute("id", idName);
removeBtn.setAttribute("onClick", `removeItem(${idName})`);
removeBtn.innerHTML = "X";
list.appendChild(node);
list.appendChild(removeBtn);
document.getElementById("output").appendChild(list);
note += 1;
}
function removeItem(name) {
var parent = document.getElementById("output");
var child = document.getElementById(name);
parent.removeChild(child);
}
In my comment, I suggested that you listen to click event bubbling from the removeBtn. In this case, all you need is to remove the onclick attribute assignment logic from your code, and instead give your removeButton an identifiable property, such as a class. Lets give it a class of delete-button:
var removeBtn = document.createElement("button");
removeBtn.classList.add('delete-button');
removeBtn.type = 'button';
removeBtn.innerHTML = 'X';
Then, you can listen to the click event at the level of #output, which is guaranteed to be present at runtime. When the event is fired, you simply check if the event target has the identifiable property, e.g. the remove-button class in our case:
output.addEventListener('click', function(e) {
// GUARD: Do nothing if click event does not originate from delete button
if (!e.target.matches('.remove-button')) {
return;
}
// Delete parent node
e.target.closest('li').remove();
});
If the click event did not originate from the remove button, we simply return and don't do anything else. Otherwise, we know that the button has been clicked, and we can then use Element.closest(), i.e. .closest('li') to retrieve the closest <li> parent node and delete it.
If you absolutely have to support IE11 (which in turn, does not support Element.closest()), you can also use Node.parentNode to access and delete the <li> element, assuming that your remove button is a direct child of the <li> element:
// Delete parent node
e.target.parentNode.remove();
See proof-of-concept below:
var rows = 10;
var output = document.getElementById('output');
for (var i = 0; i < rows; i++) {
var list = document.createElement('li');
var node = document.createTextNode('Testing. Row #' + i);
var removeBtn = document.createElement("button");
removeBtn.classList.add('remove-button');
removeBtn.type = 'button';
removeBtn.innerHTML = 'X';
list.appendChild(node);
list.appendChild(removeBtn);
output.appendChild(list);
}
output.addEventListener('click', function(e) {
// GUARD: Do nothing if click event does not originate from delete button
if (!e.target.matches('.remove-button')) {
return;
}
e.target.closest('li').remove();
});
<ul id="output"></ul>
The issue is that you have missing quotes around the id that you pass to removeItem:
removeBtn.setAttribute("onClick", `removeItem(${idName})`);
This should be:
removeBtn.setAttribute("onClick", `removeItem('${idName}')`);
Better pattern
It is better practice to bind the click handler without relying on string evaluation of code, and without needing to create dynamic id attribute values:
removeBtn.addEventListener("click", () => removeItem(list));
And then the function removeItem should expect the node itself, not the id:
function removeItem(child) {
child.parentNode.removeChild(child);
}
You can remove the following code:
var idName = "note" + note;
list.setAttribute("id", idName);

Javascript ToDo List Delete and Complete Buttons

My CodePen
So when I click the delete and complete buttons it runs these functions
function deleteListItem(){
alert("Item was deleted");
}
function completeListItem(){
alert("This item was completed");
}
for both buttons. I want to know how I can use event delegation to separate these functions, that way whenever I click the complete button it isn't running both functions.
In your javascript, when you declare deleteButton and completeButton they are both assigned the same element, the ul. That element contains the entire list. That is not what you want, you want to handle clicks on the buttons. deleteButton should be assigned to your delete button element and your completeButton to your complete button element. To do this, simply use the ID of the buttons you want instead of the ID of the UL.
In you code, change this:
var deleteButton = document.getElementById("todo");
deleteButton.addEventListener("click", deleteListItem);
var completeButton = document.getElementById("todo");
completeButton.addEventListener("click", completeListItem);
To this:
var deleteButton = document.getElementById("Remove");
deleteButton.addEventListener("click", deleteListItem);
var completeButton = document.getElementById("Complete");
completeButton.addEventListener("click", completeListItem);
EDIT:
Since your buttons are not unique you should not use an id to add the event listener. You should use a class and assign the event listener to all the elements with the class by looping threw them. In your html add a class attribute to your buttons like this: <button class="Remove"><i class="fa fa-trash" aria-hidden="true"></i></button>. Then handle the events this way:
var deleteButtons = document.getElementsByClassName("Remove");
for (var i = 0; i < deleteButtons.length; i++) {
deleteButtons[i].addEventListener('click', deleteListItem, false);
}
var completeButton = document.getElementsByClassName("Complete");
for (var i = 0; i < completeButton.length; i++) {
completeButton[i].addEventListener('click', completeListItem, false);
}
var deleteButton = document.getElementById("Remove");
deleteButton.addEventListener("click", deleteListItem);
var completeButton = document.getElementById("Complete");
completeButton.addEventListener("click", completeListItem);
Assign addEventListener to specific id of the button. id todo is the ul so clicking anything inside ul will run both functions

How to write an onclick function for a dynamically generated button

I have some buttons that look like this.
It is a "whitelist" of websites. I'd like for the button to remove the corresponding site from the whitelist.
However, since these buttons are generated with each addition of a site (entered by the user), I don't know how to get the ElementID to use in my function.
Here is where the button is generated:
var cellWebsite = document.createElement("td");
var website = document.createTextNode(array[i]);
//append cell text to cell, then cell to row (like setting a "stage")
cellWebsite.appendChild(website);
row.appendChild(cellWebsite);
//create a cell & cell text for BUTTON
var cellDelete = document.createElement("td");
var button = document.createElement("BUTTON"); //has its own element
var text = document.createTextNode("x");
button.appendChild(text);
cellDelete.appendChild(button);
row.appendChild(cellDelete);
How do I get the ID so I can write a function for when the X button is clicked? Within that function, how can I get the website that corresponds to that button?
I'm making a Chrome Extension and using chrome's local storage, if it matters.
The easiest way is to add an event listener the button variable like so:
const btn = document.createElement('button');
btn.innerText = "Click me!";
btn.addEventListener('click', function(event) {
console.log('Fired!');
});
I cannot seem to comment since I need 50 rep. for it, but can't you give it an increment? With each add just increment the ID or name with 1, and then u could target the ID or name.
Check the inspection view of your browser and see if id and other attributes are set.
If this didn't work, make use of the form id attribute the index of the element as፡
var x = document.getElementById("myForm").elements[0].value;
If no id provided for form:
var x = document.forms[0].id;
Or
var x = document.forms.item(0).id;
When your element is dynamically created, You should event delegation to handle event.
Event delegation allows you to avoid adding event listeners to specific nodes; instead, the event listener is added to one parent. That event listener analyzes bubbled events to find a match on child elements.
Example:
var counter = -1;
function addRow() {
counter++;
var table = document.getElementById( 'myTable' ),
row = table.insertRow( counter ),
cell = row.insertCell( 0 ),
cellDelete = row.insertCell( 1 ),
button = document.createElement( 'button' ),
text = document.createTextNode( 'X' );
cell.innerHTML = 'wikipedia.org ' + counter;
button.appendChild( text );
cellDelete.appendChild( button );
button.addEventListener( 'click', function ( e ) {
table.deleteRow( e.target.parentNode.parentNode.rowIndex );
counter--
} )
}
body {
margin: 0
}
table {
width: 100%
}
td {
padding: 8px;
border-bottom: 1px solid #ddd
}
td:nth-child(even) {
text-align: right
}
tr:nth-child(odd) {
background-color: #efefef
}
<button type="button" onclick="addRow()">Add new row</button>
<br>
<table id="myTable"></table>

Javascript - Listener executing on assignment

So, I'm currently working on a HTML page that displays a table with an editable text box and a delete button for the row for every quote in a list. The list is fetched from a stored file, so I need to dynamically generate this table and its rows every time I fetch it. However, when this code runs, the table generated is empty, because when the listener is added, the delete row function executes and just removes the row right after it's added.
for (var i = 0; i < quotesArray.length; i++) {
//Insert a new row into the table.
var newQuoteRow = quoteList.insertRow(-1);
var cellOne = newQuoteRow.insertCell(0);
var cellTwo = newQuoteRow.insertCell(1);
//Insert editable text boxes for a quote into the row.
var quoteInput = document.createElement('input');
quoteInput.value = quotesArray[i];
quoteInput.className = "quote";
cellOne.appendChild(quoteInput);
//Put a delete button at the end of the row.
var deleteQuoteButton = document.createElement('button');
deleteQuoteButton.innerHTML = "x";
cellTwo.appendChild(deleteQuoteButton);
deleteQuoteButton.addEventListener('click', deleteCurrentQuoteRow(deleteQuoteButton));
}
});
}
function deleteCurrentQuoteRow(buttonToDelete) {
var currentRow = buttonToDelete.parentNode.parentNode; //get the grandparent node, which is the row containing the cell containing the button.
currentRow.parentNode.removeChild(currentRow); //delete the row in the table
}
From what I understand, this problem occurs because the function linked to in the addEventListener method has a parameter, which causes it to execute immediately instead of waiting for a click. However, I can't think of a way to implement this without passing the button being clicked as the parameter, because then I won't know which row to delete. How can I fix this so that the table will actually populate, and the delete button will actually delete a row?
Currently you are invoking the function deleteCurrentQuoteRow and assigning its return value which is undefined as event listener.
Use
deleteQuoteButton.addEventListener('click', function(){
deleteCurrentQuoteRow(this); //Here this refers to element which invoke the event
});
OR, You can modify the function deleteCurrentQuoteRow as
function deleteCurrentQuoteRow() {
var currentRow = this.parentNode.parentNode; //get the grandparent node, which is the row containing the cell containing the button.
currentRow.parentNode.removeChild(currentRow); //delete the row in the table
}
Then you can just pass the function reference as
deleteQuoteButton.addEventListener('click', deleteCurrentQuoteRow);

Can't properly delete rows from a dynamically generated table using a button

I have the following code which is supposed to generate rows in a table where each row has its own content and delete button.
<!DOCTYPE html>
<html>
<head>
<title>table</title>
</head>
<body>
<input id="inputText">
<button onclick = "addRow()">Add text</button>
<table id = "table">
</table>
<script>
function addRow(){
var newRow = document.createElement("tr");
var col1 = document.createElement("td");
var col2 = document.createElement("td");
newRow.appendChild(col1);
newRow.appendChild(col2);
var button = document.createElement("button");
button.innerHTML = "delete";
button.onclick = function () {
var index = this.parentNode.parentNode.rowIndex;
document.getElementById("table").deleteRow(index);
}
col1.appendChild(button);
var enteredText = document.getElementById("inputText").value;
col2.innerHTML = enteredText;
document.getElementById("table").appendChild(newRow);
}
</script>
</body>
</html>
The problem is that no matter which delete button I press, it deletes the last row.
I tried using console.log(this.parentNode.parentNode) to see if it returns the right <tr> object, and it indeed does. But for some reason, the attribute rowIndex is -1 no matter what button is pressed; hence only the last row is deleted. Does it mean that each dynamically generated <tr> doesn't know its row index?
You can use HTMLTableElement.insertRow() function instead.
var newRow = document.getElementById("table").insertRow();
// newRow.rowIndex will return you the proper index
Here is a working fiddle
Update
It was a bug in the Webkit layout engine, (that moved to the forked Blink engine as well). This is why it works well in Firefox but not in earlier versions of Chrome (Blink) or Safari (Webkit).
The bug report is here, it's fixed now.
There are numerous way to achieve what you require. Here is another such example that is based on the code that you posted. Hopefully it will give you some further ideas.
(function() {
// create references to static elements, no need to search for them each time
var inputText = document.getElementById("inputText"),
butAdd = document.getElementById("butAdd"),
table = document.getElementById("table");
// a generic function for finding the first parent node, starting at the given node and
// of a given tag type. Retuns document if not found.
function findParent(startNode, tagName) {
var currentNode,
searchTag;
// check we were provided with a node otherwise set the return to document
if (startNode && startNode.nodeType) {
currentNode = startNode;
} else {
currentNode = document;
}
// check we were provided with a string to compare against the tagName of the nodes
if (typeof tagName === 'string') {
searchTag = tagName.toLowerCase();
} else {
currentNode = document;
}
// Keep searching until we find a parent with a mathing tagName or until we get to document
while (currentNode !== document && currentNode.tagName.toLowerCase() !== searchTag) {
currentNode = currentNode.parentNode;
}
// return the match or document
return currentNode;
}
// for deleting the current row in which delete was clicked
function deleteRow(e) {
// find the parent with the matching tagName
var parentTr = findParent(e.target, 'tr');
// did we find it?
if (parentTr !== document) {
// remove it
parentTr.parentNode.removeChild(parentTr);
}
}
// for adding a row to the end of the table
function addRow() {
// create the required elements
var newRow = document.createElement("tr"),
col1 = document.createElement("td"),
col2 = document.createElement("td"),
button = document.createElement("button");
// add some text to the new button
button.appendChild(document.createTextNode("delete"));
// add a click event listener to the delete button
button.addEventListener('click', deleteRow, false);
// append all the required elements
col1.appendChild(button);
col2.appendChild(document.createTextNode(inputText.value));
newRow.appendChild(col1);
newRow.appendChild(col2);
// finally append all the elements to the document
table.appendChild(newRow);
}
// add click event listener to the static Add text button
butAdd.addEventListener('click', addRow, false);
}());
<input id="inputText">
<button id="butAdd">Add text</button>
<table id="table"></table>

Categories