javascript loop: variable equals the last iteration - javascript

The code below will add element once user clicks addmore link.
The problem arrives when the user clicks the remove link.
I have something like these on my code
<script language="JavaScript">
var count=1;
function addmore() {
alert(count);
var printme = "<table id='table"+count+"'><tr><td><a href='#' onclick='remove(count)'>remove</a></td></tr></table";
//(other code here)...
count++;
}
function remove(y) {
alert(y)
var tab = 'table'+y;
document.getElementById(tab).style.display = "none";
}
</script>
I used the alert here so I can easily monitor the value of count it gives.
What happens here is that the value of 'y' (on remove function) always the same, which is the last value of count in the loop.
For example I click the link addmore 3 times, therefore the last value of my 'count=4'.
And let say I wanted to remove the 3rd element which at this point when i clicked the remove link, it must have pass argument like this remove(3). But what happens here is whatever element i clicked it seems like it always passing argument this way remove(4)

That's because you have count as a global variable.
Try .....onclick='remove("+count+")'.... to sort of "lock in" the value.

Please try this:
var printme = "<table id='table"+count+"'><tr><td><a href='#' onclick='remove("+count+")'>remove</a></td></tr></table";
also try following line remove function:
document.getElementById(""+tab+"").style.display = "none";

All previous answers are correct, onclick refers to the current variable count when remove is called.
When you generate the text for the table you use the value of count as it is then:
onclick='remove('+count+')...
You can leave out the id's and count altogether using this:
onclick='remove(this.parentElement.parentElement.parentElement);'...
function remove(elementToRemove){
elementToRemove.parentElement.removeChild(elementToRemove);
}

maybe just onclick='remove('+count+')'
You can do something like
<html>
<head>
<script type="text/javascript">
var count=1;
function addmore() {
var id = 'table' + count;
var table = document.createElement('table');
table.setAttribute('id', id);
var tr = document.createElement('tr');
var td = document.createElement('td');
var a = document.createElement('a');
a.setAttribute('href', '#');
a.appendChild(document.createTextNode('remove ' + id));
a.onclick = function() {
table.style.display = 'none';
document.body.removeChild(table);
};
td.appendChild(a);
tr.appendChild(td);
table.appendChild(tr);
document.body.appendChild(table);
count++;
}
</script>
</head>
<body>
Add Table
</body>
</html>
With table reference and onclick defined like this you don't need id

Related

Why does my button click listener not work in chrome extension?

I'm trying to create a chrome extension, my problem is that when I try to place an event listener to each button in a class, only the first button has one, and the rest don't have an event listener.
function copyButtonInitialise(){
var copyButtons = document.getElementsByClassName("copyPassword");
console.log("length = ", copyButtons.length);
for (var i = 0; i < copyButtons.length; i++){
console.log(copyButtons[i] + " element number " + i + "= button");
copyButtons[i].addEventListener("click", copyButtonClick);
}
}
This function is what should be called if any button with the class "copyPasword" is clicked.(just want to make sure it gets clicked, but it doesn't)
function copyButtonClick(){
console.log("Hello There");
}
This is the function that loads passwords, it's called before adding event listeners to buttons.
async function loadPasswords(){
document.getElementById("passwordTable").innerHTML = "";
console.log("This is the loadpasswords function");
chrome.storage.sync.get(null, function(items) {
var allKeys = Object.keys(items);
var passwordTable = document.getElementById("passwordTable");
var header = passwordTable.createTHead();
var passwordRow = header.insertRow(0);
for(var i = 0; i < allKeys.length; i++){
let passwordKey = allKeys[i];
chrome.storage.sync.get([allKeys[i]], function(value){
var passwordName = Object.keys(value);
passwordName = passwordName[0];
var table = document.getElementById("passwordTable");
var header = table.createTHead();
var passwordRow = header.insertRow(0);
var cellTwo = passwordRow.insertCell(0);
var cell = passwordRow.insertCell(1);
cellTwo.innerHTML = "<p1 id=passwordNameCol>" + passwordName + "</p1>";
cell.innerHTML = "<button class=copyPassword> Copy " + '"'+ passwordName + '"'+ "</button>";
});
}
});
}
The passwords clearly load in.
When I click the buttons, nothing gets sent to the console, expecting a "hello there" (as shown above)
Try these things:
the outer chrome.storage.sync.get(null returns all stored couples key+value.
Why you use chrome.storage.sync.get a second time inside the "for" statement? It is not necessary.
Don't use insert methods of table but try with createElement and appendChild.
Create first an THEAD (or TBODY) element and then put every rows on it.
When you'll finish you'll have to append only that THEAD\TBODY as child of your table.
Try to create the button with createElement (as i suggest for any other table elements) and after its creation put the event listener on it (inside the "for").
if you think to reuse the same table for other differente rows remenber to destroy the THEAD first otherwise the just created events listeners will remain orphans.
Destroy the THEAD with something like element.remove() and not with innerHTML = "".

how to pass a reference to the current object in href?

I need to pass a reference to current element that is being clicked in href tag.
Consider this code which goes in a loop when creating a table
td=document.createElement("td");
td.innerHTML='click me';
But this doesn't work because it points to the browser window so when I am setting it to something the whole page replaced the value I am setting it to. So how do I pass the reference to <a> object into some_function() ?
where some_function() is declared like:
function some_function(clicked_object,param2,param3) {
clicked_object.style.backgroundColor="red"
}
Here's a full fledged solution that avoids inline code:
for (var i = 0; i < 10; i++) {
// create elements
let td = document.createElement("td");
let a = document.createElement("a");
a.innerHTML = `cell #${i}`;
a.href = ""; // we need this so <a> appears as link
// set click handler
a.addEventListener("click", some_function);
// add some data
a.dataset.rowNumber = 1;
a.dataset.extra = i * 2 + 7;
td.appendChild(a);
row.appendChild(td);
}
function some_function(e) {
e.preventDefault(); // stop default event handling
let clicked_object = e.target; // get clicked element from event
clicked_object.style.backgroundColor = "red";
console.log("param:", clicked_object.dataset.extra);
}
<table>
<tbody>
<tr id="row"></tr>
</tbody>
</table>
Edit: added data to elements

get javascript dynimcally created control state

I'm dynamically adding some rows to my ASP.NET table, I have several cells in each row and each cell contains a control which is dynamically created:
var TD = document.createElement('td');
var spanCheck = document.createElement("span");
spanCheck.innerHTML = "<input type='checkbox' name='vehicle' value='Car'>mycheck";
spanCheck.id = "newfoodcheck0";
spanCheck.onclick = function () {
if (spanCheck.checked)
alert('checked');
else
alert('unchecked');
};
TD.appendChild(spanCheck);
I'm adding an onclick function for this span (which is rendered as a checkbox), I want to know when it is checked, but if (spanCheck.checked) doesn't work and I always get 'unchecked' in my alert, what is going wrong here? should I use spanCheck.checked or I should use document.getElementById(spanCheck.id).checked? I've tested it, but again with no luck! how can I know whether my checkbox is checked or know?
What you are doing is adding click event on spanCheck and checking for spanCheck.checked. However the checked property is on the input element which is the child of the spanCheck. You might want to do somewhat like this:
var TD = document.createElement('td');
var spanCheck = document.createElement("span");
spanCheck.innerHTML = "<input id='my_input' type='checkbox' name='vehicle' value='Car'>mycheck";
spanCheck.id = "newfoodcheck0";
spanCheck.onclick = function () {
var input = document.getElementById('my_input');
if (input.checked)
alert('checked');
else
alert('unchecked');
};
Also, I think you haven't inserted your TD into the body. So in the last line, you should use appendChild:
TD.appendChild(spanCheck);
document.body.appendChild(TD);
Another thing, you should not attach onclick event on the span. You should attach the same on input element. The following code is doing the same:
var TD = document.createElement('td');
var spanCheck = document.createElement("span");
spanCheck.innerHTML = "<input id='my_input' type='checkbox' name='vehicle' value='Car'>mycheck";
spanCheck.id = "newfoodcheck0";
TD.appendChild(spanCheck);
document.body.appendChild(TD);
var input = document.getElementById('my_input');
input.onclick = function () {
if (input.checked)
alert('checked');
else
alert('unchecked');
};
In your code, spanCheck is not rendered as a checkbox. It contains a checkbox. Therefore, there's no such property spanCheck.checked. There is a spanCheck.children[0].checked property, however.

par.rowIndex is null in this code

I'm really new to JavaScript but I can't find out why this program won't work.
I want when I click the dynamically created button which is situated in a cell in my dynamically created table to get the rowindex of the row in which the button is situated.
Thanks in advance - here is my code:
<html>
<head>
<script>
function whichrow(obj) {
var par = obj.parentNode;
while(par.nodeName.toLowerCase()! = 'tr') {
par = par.parentNode;
}
alert(par.rowIndex);
}
</script>
</head>
<body>
<script>
mybody = document.getElementsByTagName("body")[0];
mytable = document.createElement("table");
mytablebody = document.createElement("tbody");
for(var i = 0; i<5; i++) {
mycurrent_row = document.createElement("tr");
mycurrent_row.id = "row"+i;
for(var j = 0; j<4; j++) {
mycurrentcell = document.createElement("td");
currenttext = document.createTextNode("Row" + i + "Column" + j);
mycurrentcell.appendChild(currenttext);
mycurrent_row.appendChild(mycurrentcell);
}
mybutoncell = document.createElement("td");
but = document.createElement("button");
mybutoncell.appendChild(but);
mycurrent_row.appendChild(mybutoncell);
mytablebody.appendChild(mycurrent_row);
but.onClick = whichrow(this);
}
mytable.appendChild(mytablebody);
mybody.appendChild(mytable);
mytable.setAttribute("border", "2");
</script>
</body>
</html>
Ok, so a few points to note here.
In the javascript eventing system, the system calls your callback with its own event object containing different properties according to what happened.
So, here are the mistakes:
When you're assigning to the event handler, when you say but.onclick = whichrow(this) you're setting but.onclick to the result of whichrow, which is undefined since you're not returning anything anyway. It should be but.onclick = whichrow; which will call whichrow when the user clicks your button. The parameter passed is a MouseEvent object. The link I've supplied should serve as a good start to read up on what kind of properties are available to you.
I have to check, since I use el.addEventListeners a lot, but onclick needs to be in lower case, not camelCase like you've done.
Inside the event callback, this usually refers to the element that was clicked, so you should use that.
There is no rowIndex property.
Now, trying to find a solution to your problem. rowIndex can be gleaned by traversing the dom. I'm not sure what purpose this will serve since you're creating the DOM by hand anyway and know the rowIndex already, but if it were unknown, here's what I would do
function whichRow(e) {
// here this should be the button.
var curRow = this.parentElement.parentElement,
rowIndex = 0;
while(curRow) {
curRow = curRow.previousElementChild;
rowIndex++;
}
return rowIndex;
}
I'm writing this off the top of my head, but the point is to give the main idea. In the above snippet, I've taken the parent of the parent of the button, since here's the approximate markup of the button section:
<tr>
<td>
<button></button>
</td>
</tr>
so, the parentElement of the parentElement of the button element should give you the <tr>. Then we'll traverse backwards till we don't have any previous elements, counting as we go. Once the previous element is null, return the count.
The obj you are passing to whichrow() is a button, which I assume inside a TD. So your while loop will exit in its first iteration itself, resulting in par holding a TD - which does not have a property named rowIndex

Javascript removeChild array

this looks simple enough but I just can't get it to work. I could add DOM elements but I just can't remove them when using an array.
<script language="javascript">
fields = 0;
count = 0;
function addInput() {
if (fields != 10) {
var htmlText = "<input type='search' value='' name='field[]' />";
var remButton = "<input type='button' value='del' onclick='remove()' />";
var newElement = document.createElement('div');
newElement.id = 'SomeID'+fields;
newElement.innerHTML = htmlText + remButton + newElement.id;
var fieldsArea = document.getElementById('text');
fieldsArea.appendChild(newElement);
fields += 1;
} else {
...
}
count++;
}
// NEED HELP FROM HERE PLEASE
// You don't need to Loop, just get the button's id and remove that entire 'SomeID'
function remove() {
fieldsArea = document.getElementById('text');
fieldsArea.removeChild(SomeID1); <-----------------------THIS WORKS!
fieldsArea.removeChild(SomeID+count); <------------------THIS JUST WOULDN'T
count--;
}
</script>
In the remove function, writing SomeID1 works and delete the first added element but when I try to use a 'count', I just can't delete my 'elements'.
Any help would be most appreciated.
Thank you!
You have to get a reference to the element first. Currently you are passing an undefined variable SomeID to the function.
E.g.:
var element = document.getElementById('SomeID' + fields);
// or starting by zero: var element = document.getElementById('SomeID0');
element.parentNode.removeChild(element);
If you want to remove the div for which the button was clicked, you have to pass a reference to the corresponding div to the remove function.
'<input type="button" value="del" onclick="remove(this.parentNode)" />';
this will refer to the button and as it is a child of the div, this.parentNode refers to that div.
You also have to change your function to accept the element that should be removed:
function remove(element) {
element.parentNode.removeChild(element);
count--;
}
You probably also have to update fields, but I'm not sure how your code is supposed to work.
If you want to remove all of them you have to loop:
for(;fields--;) {
var element = document.getElementById('SomeID' + fields);
element.parentNode.removeChild(element);
}
Also have a look at the documentation of removeChild.
The removeChild needs a node (DOM element) as parameter. In this case
fieldsArea.removeChild(SomeID+count);
you could for example pass the node this way
fieldsArea.removeChild(document.getElementById('SomeID'+count));

Categories

Resources