Javascript Loop Button always takes last value - javascript

I have a function that crawls infos from tmdb. i want to work with that response. i do for example search for a movie and want to put the results(titles and the poster-images) into a table with a button.
That works fine.
For that i have a loop that creates a table with entries every loop. In 1 entry i have a button, that is supposed to call another function and give it the value(form the poster-path the movie has) that is set in the specific loop. Works partially...Problem is: the value given to the new fuction is always the last value (value of the last loop). I dont know how to fix that :/
I already tried an "Immediately-Invoked Function Expression"(found in this forum) which looks like this
for (var i = 0; i < 3; i++) {
(function(index) {
console.log('iterator: ' + index);
})(i);
}
Same Problems still :/
thats my script ("bbcode" and "imglink" were set before this)
if (this.status === 200) {
var jsonResponse = JSON.parse(this.responseText);
totalresults = jsonResponse.total_results;
if (totalresults === 0){ noresult(); }
if (totalresults === 1){ oneresult(); }
else {
var x = document.createElement("TABLE");
x.setAttribute("id", "myTable");
x.setAttribute("border", "1");
document.getElementById("log").appendChild(x);
for (var j = 0; j < totaresults; j++) {
(function(i) {
posterpath = jsonResponse.results[i].poster_path;
newbbcode = bbcode.replace(imglink, "http://image.tmdb.org/t/p/w400"+ posterpath);
var y = document.createElement("TR");
y.setAttribute("id", "myTr" + i);
document.getElementById("myTable").appendChild(y);
var z = document.createElement("TD");
var t = document.createTextNode(jsonResponse.results[i].title);
z.appendChild(t);
document.getElementById("myTr" + i).appendChild(z);
var z = document.createElement("TD");
var t = document.createElement("IMG");
t.setAttribute("src", "http://image.tmdb.org/t/p/w92"+jsonResponse.results[i].poster_path);
z.appendChild(t);
document.getElementById("myTr" + i).appendChild(z);
var z = document.createElement("TD");
var t = document.createElement("INPUT");
t.setAttribute("type","button");
t.setAttribute("value","pick this");
t.addEventListener("click", function(){workwithnewbbcode(newbbcode)} );
z.appendChild(t);
document.getElementById("myTr" + i).appendChild(z);
})(j);
}
}
Maybe someone has a very simple (noob friendly^^) idea to do that with javascript.
Thank you guys!
EDIT: Thanks to Jaromanda X for the solution!
instead of
newbbcode = bbcode.replace(imglink, "http://image.tmdb.org/t/p/w400"+ posterpath);
just add var
var newbbcode = bbcode.replace(imglink, "http://image.tmdb.org/t/p/w400"+ posterpath);
OR
if (this.status === 200) {
var jsonResponse = JSON.parse(this.responseText);
totalresults = jsonResponse.total_results;
if (totalresults === 0) {
noresult();
} else if (totalresults === 1) {
oneresult();
} else {
var table = document.createElement("TABLE");
table.id = "myTable";
table.border = "1";
jsonResponse.results.forEach(function(result) {
var posterpath = result.poster_path;
var newbbcode = bbcode.replace(imglink, "http://image.tmdb.org/t/p/w400" + posterpath);
var tr = document.createElement("TR");
var td1 = document.createElement("TD");
td1.appendChild(document.createTextNode(result.title));
tr.appendChild(td1);
var td2 = document.createElement("TD");
var img = document.createElement("IMG");
img.src = "http://image.tmdb.org/t/p/w92" + posterpath;
td2.appendChild(img);
tr.appendChild(td2);
var td3 = document.createElement("TD");
var input = document.createElement("INPUT");
input.type = "button";
input.value ="pick this";
input.addEventListener("click", function() {
workwithnewbbcode(newbbcode);
});
td3.appendChild(input);
tr.appendChild(td3);
table.appendChild(tr);
});
document.getElementById("log").appendChild(table);
}
}

Consider the following example:
for (var i=0;i<10;i++){
setTimeout(function(){
console.log(i);
},1000);
}
You will always get 10 in the output because by the time the nested function is called, the variable i already reached the end of the loop.
In your case, your response object arrives in an XHR callback. This has the same flow as setTimeout. You can create a function wrapper to keep the iterator variable in the call stack:
var myfunc=function(x){ //a function that returns a function
setTimeout(function(){
console.log(x);
},1000);
}
for (var i=0;i<10;i++) myfunc(i);

Related

React Error : (function) is not defined at HTMLButtonElement.onclick

I am using ReactJS and I am creating a button "remove" in a method called showData() and appending it to a row in a table of people.
I am setting its attribute onclick to my method removePerson() implemented in the same class of the method showData().
This is all good until I click on the button "remove" - then an error shows:
ReferenceError: removePerson() is not defined at HTMLButtonElement.onclick
This is my code:
showData() {
let localStoragePersons = JSON.parse(localStorage.getItem("personsForms"));
persons = localStoragePersons !== null ? localStoragePersons : [];
let table = document.getElementById('editableTable');
let x = table.rows.length;
while (--x) {
table.deleteRow(x);
}
let i = 0;
for (i = 0; i < persons.length; i++) {
let row = table.insertRow();
let firstNameCell = row.insertCell(0);
let lastNameCell = row.insertCell(1);
let birthdayCell = row.insertCell(2);
let salaryCell = row.insertCell(3);
let choclatesCell = row.insertCell(4);
let genderCell = row.insertCell(5);
let workTypeCell = row.insertCell(6);
let hobbiesCell = row.insertCell(7);
let descriptionCell = row.insertCell(8);
let colorCell = row.insertCell(9);
firstNameCell.innerHTML = persons[i].firstName;
lastNameCell.innerHTML = persons[i].lastName;
birthdayCell.innerHTML = persons[i].birthday;
salaryCell.innerHTML = persons[i].salary;
choclatesCell.innerHTML = persons[i].Choclates;
genderCell.innerHTML = persons[i].Gender;
workTypeCell.innerHTML = persons[i].workType;
hobbiesCell.innerHTML = persons[i].Hobbies;
descriptionCell.innerHTML = persons[i].Description;
colorCell.innerHTML = persons[i].favoriteColor;
colorCell.style.backgroundColor = persons[i].favoriteColor;
let h = persons[i].ID;
let removeButton = document.createElement('button');
removeButton.setAttribute('onclick', 'removePerson(' + h + ')')
removeButton.innerHTML = 'Remove';
row.appendChild(removeButton);
}
}
I tried to change the code
removeButton.setAttribute('onclick', 'removePerson(' + h + ')');
to
removeButton.onclick = this.removePerson(h);
but everyTime the "showData()" method runs this method "removePerson()" run also and i don't want this to happen.
removePerson(ID) {
alert(ID);
let table = document.getElementById('editableTable');
if (persons.length === 1) {
table.deleteRow(1);
persons.pop();
localStorage.setItem("personsForms", JSON.stringify(persons));
}
let target;
let i;
for (i = 0; i < persons.length; i++) {
if (persons[i].ID === ID) {
target = persons[i].firstName;
persons.splice(i, 1); break;
}
}
for (i = 1; i < table.rows.length; ++i) {
let x = table.rows[i];
if (x.cells[0].innerHTML === target) {
table.deleteRow(i); break;
}
}
let temp = [];
let j = 0;
for (i = 0; i < persons.length; ++i) {
if (persons[i] !== null) {
temp[j++] = persons[i];
}
}
persons = temp;
localStorage.clear();
localStorage.setItem("personsForms", JSON.stringify(persons));
this.showData();
}
When you set a variable to some value, the value is computed first.
Hence, when you write removeButton.onclick = this.removePerson(h); the right side of the equation is evaluated first.
You can wrap it with a fat-arrow function, so that the function that will be called upon user click would be the function that calls this.removePerson(h). This way its value is a lambda function, and not the actual value of this.removePerson(h):
removeButton.onclick = () => this.removePerson(h);

How to get associative array elements and names. JS

Problem: Trying to get certain elements from a associative array, by using a loop. The loop is for multiple times i will go through. This associative array is associated to an array key. Ex: {eid0:{...},eid1:{...}}
It's to update a page with JS using DOM an no refresh. I've gone over StackOverflow and some other sites. I've looked in books. I can't seem to figure it out.
function display_oddsbet(id) {
var ds = document.getElementById("ds");
var tr = document.createElement("tr");
var td = document.createElement("td");
var tr0 = document.createElement("tr");
var tr1 = document.createElement("tr");
var tbl = document.createElement("table");
var tdsp = document.createElement("td");
var tdlg = document.createElement("td");
var tdloc = document.createElement("td");
var tda = document.createElement("td");
var tdh = document.createElement("td");
var tdsd = document.createElement("td");
var i;
var cnt= 0;
for (var s in id) {
var v = id[s];
for (var t in v) {
var k = v[t];
// for (var f in k) {
var ed = "eid" + cnt;
var i = v[ed];
cnt++;
console.log(i);
tr.classList = "eid" + cnt;
var a = i.awayteam_name;
var h = i['hometeam_name'];
var sd = i['startdate'];
var sport = i['sport_name'];
var league = i['league_name'];
var loc = i['location_name'];
tdsp.innerHTML = sport;
tdlg.innerHTML = league;
tdloc.innerHTML = loc;
tr0.appendChild(tdsp);
tr0.appendChild(tdloc);
tr0.appendChild(tdlg);
tbl.appendChild(tr0);
tda.innerHTML = a;
tdh.innerHTML = h;
tdsd.innerHTML = sd;
tr1.appendChild(tdsd);
tr1.appendChild(tda);
tr1.appendChild(tdh);
tbl.appendChild(tr1);
tr.appendChild(tbl);
// left
if (i['oddsbet'] == "1") {
td.innerHTML = "1";
td.style = "oddsbet";
tr.appendChild(td);
}
// 2 is on right
if (i['oddsbet'] == "2") {
td.innerHTML = "2";
td.classList = "oddsbet";
tr.appendChild(td);
}
// middle
else {
td.innerHTML = i['oddsbet'];
td.classList = "oddsbet";
tr.appendChild(td);
}
ds.appendChild(tr);
// }
}
}
return;
}
I get nothing doing this. I need to get i['awayteam_name']; and the rest from an API.
Don't ever forget. Garbage in Garbage out..
function display_oddsbet(id) {
var ds = document.getElementById("ds");
var tr = document.createElement("tr");
var td = document.createElement("td");
var tr0 = document.createElement("tr");
var tr1 = document.createElement("tr");
var tbl = document.createElement("table");
var tdsp = document.createElement("td");
var tdlg = document.createElement("td");
var tdloc = document.createElement("td");
var tda = document.createElement("td");
var tdh = document.createElement("td");
var tdsd = document.createElement("td");
Object.keys(id).forEach(function(key, index) {
var j = this[key];
Object.keys(j).forEach(function(key, index) {
//console.log(this[index]);
var ed = "eid" + cnt;
//var i = v[ed];
cnt++;
console.log(j[key]);
tr.classList = "eid" + cnt;
var a = j[key].awayteam_name;
var h = j[key]['hometeam_name'];
var sd = j[key]['startdate'];
var sport = j[key]['sport_name'];
var league = j[key]['league_name'];
var loc = j[key]['location_name'];
tdsp.innerHTML = sport;
tdlg.innerHTML = league;
tdloc.innerHTML = loc;
tr0.appendChild(tdsp);
tr0.appendChild(tdloc);
tr0.appendChild(tdlg);
tbl.appendChild(tr0);
tda.innerHTML = a;
tdh.innerHTML = h;
tdsd.innerHTML = sd;
tr1.appendChild(tdsd);
tr1.appendChild(tda);
tr1.appendChild(tdh);
tbl.appendChild(tr1);
tr.appendChild(tbl);
// left
if (j[key].oddsbet == "1") {
td.innerHTML = "1";
td.style = "oddsbet";
tr.appendChild(td);
}
// 2 is on right
if (j[key].oddsbet == "2") {
td.innerHTML = "2";
td.classList = "oddsbet";
tr.appendChild(td);
}
// middle
else {
td.innerHTML = j[key].oddsbet;
td.classList = "oddsbet";
tr.appendChild(td);
}
ds.appendChild(tr);
// }
}, j);
}, id);
return;
}

How to access dynamically created button?

btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update0';
btnUpdate.appendChild(t);
tabCell.appendChild(btnUpdate);
I have a simple line of code where I have created a button with my javascript. How do I access this button through the same javascript file? I want to add onClick feature to it.
document.getElementById("update0").onclick = edit_row(0);
I tried doing so by adding the above line of code, but now it won't display the table but straight away jumps to the edit_row() function.
Edit:
function showCustomer() {
var obj, dbParam, xmlhttp, myObj, x, txt = "",tabCell;
var btnUpdate;
obj = { "table":"Successful", "limit":20 };
dbParam = JSON.stringify(obj);
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
myObj = JSON.parse(xmlhttp.responseText);
console.log(myObj);
var col = [];
for (var i = 0; i < myObj.length; i++) {
for (var key in myObj[i]) {
if (col.indexOf(key) === -1) {
col.push(key);
}
}
}
key="Update";
col.push(key);
console.log(col);
// CREATE DYNAMIC TABLE.
var table = document.createElement("table");
// CREATE HTML TABLE HEADER ROW USING THE EXTRACTED HEADERS ABOVE.
var tr = table.insertRow(-1); // TABLE ROW.
for (var i = 0; i < col.length; i++) {
var th = document.createElement("th"); // TABLE HEADER.
th.innerHTML = col[i];
tr.appendChild(th);
}
// ADD JSON DATA TO THE TABLE AS ROWS.
for (var i = 0; i < myObj.length; i++) {
tr = table.insertRow(-1);
tabCell = null;
for (var j = 0; j < col.length-1; j++) {
tabCell = tr.insertCell(-1);
tabCell.innerHTML = myObj[i][col[j]];
}
tabCell = tr.insertCell(-1);
btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update'+i;
btnUpdate.appendChild(t);
tabCell.appendChild(btnUpdate);
}
tr = table.insertRow(-1);
tabCell = null;
for (var j = 0; j < col.length-1; j++) {
tabCell = tr.insertCell(-1);
tabCell.innerHTML = " ";
}
tabCell = tr.insertCell(-1);
var btn = document.createElement("BUTTON");
var t = document.createTextNode("Add Row");
btn.appendChild(t);
tabCell.appendChild(btn);
document.getElementById("update0").addEventListener = function (){
edit_row(0);
};
// FINALLY ADD THE NEWLY CREATED TABLE WITH JSON DATA TO A CONTAINER.
var divContainer = document.getElementById("showData");
divContainer.innerHTML = "";
divContainer.appendChild(table);
}
};
xmlhttp.open("POST", "http://localhost:8090/Vaccine", true);
xmlhttp.setRequestHeader("Content-type", "application/JSON");
xmlhttp.send("x=" + dbParam);
}
function edit_row(no)
{
alert("HELLO");
}
With this line :
document.getElementById("update0").onclick = edit_row(0);
You are not "attaching" the click event to the edit_row function. You're setting the onclick property with the result of the edit_row(0) invokation.
Also, don't use the onclick property.
Use the addEventListener function instead.
document.getElementById("update0").addEventListener("click", function () {
edit_row(0);
});
If you need a reason : by overwriting the onclick property, you could be disabling any other click event listener on your elements. By using addEventListener(), you can have several events listener on the same element/event couple.
And you can do this right after you created the button. You don't need to get it by its id later.
Your code would look like this :
btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update0';
btnUpdate.appendChild(t);
btnUpdate.addEventListener("click", function () {
edit_row(0);
});
You have to do that in callback of on click event. If you inline, it executes directly when javascript reading your code.
document.getElementById("update0").onclick = function (){
edit_row(0);
};
How do I access this button through the same javascript file?
The same way you've been accessing it all along.
It is stored in the btnUpdate variable. Use that.
but now it won't display the table but straight away jumps to the edit_row() function.
That is because you are calling edit_row and setting its return value as the click handler.
Since you want to pass arguments to it, the easiest thing to do is to create a new function.
function edit_row_first_argument_0 () {
edit_row(0);
}
button.addEventListener("click", edit_row_first_argument_0);
(You can use an anonymous function expression, I use the verbose approach above for clarity).
Try this:
btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update0';
btnUpdate.appendChild(t);
tabCell.appendChild(btnUpdate);
btnUpdate.addEventListener("click", (e) => {
// this linked to btnUpdate
// Here make whatever you want
// You can call edit_row now
edit_row(0)
})
It seems that your button is not in the DOM yet, so you are not able to find it with document. You can use the variable btnUpdate if it is in the same file like btnUpdate.onclick = function() {}, or using addEventListenerlike btnUpdate.addEventListener('click', function() {}).
Also, it seems you are executing the edit_row(0) function. You need to put it inside a function like
btnUpdate.addEventListener('click', function() {
edit_row(0);
})
You call the function when you have () at the end so
document.getElementById("update0").onclick = edit_row(0);
will immediately call edit_row
Why not do this instead:
btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update0';
btnUpdate.onclick=function() {
edit_row(this.id.replace("update","")); // or use a data-attribute
}
btnUpdate.appendChild(t);
tabCell.appendChild(btnUpdate);
or use event delegation:
Native JS equivalent to jquery delegation

Loop for creating headers and placing text into paragraphs below them

function newHeader (header) {
var head = document.createElement('h'+ header);
var hText = document.createTextNode('text for h'+ header);
head.appendChild(hText);
document.body.appendChild(head);
}
function newPara (para) {
var newP = document.createElement('p');
var newPText = document.createTextNode("text for p" + para);
newP.appendChild(newPText);
var intoH = document.getElementByTagName('h' + header);
intoH.item(0).appendChild(newP);
}
for (i = 1; i <= 6; i++) {
newHeader(i);
}
for (i = 1; i <= 6; i++) {
newPara(i);
}
What am I doing wrong?
I want to dynamically create the headers and place paragraphs with the text inside them. I was attempting to use the item() to appendChild to place the new paragraph text inside the headers accordingly but it doesn't work. I get the headers to show , but not the paragraph.
Please help!
thank you!
You're using header variable when is not defined (you should replace it by para), Also you miss s in getElementByTagName should be getElementsByTagName and that will return an array of elements so you can specify the first using [0] instead of item(0) :
document.getElementsByTagName('h' + para)[0];
Hope this helps.
function newHeader (header) {
var head = document.createElement('h'+ header);
var hText = document.createTextNode('text for h'+ header);
head.appendChild(hText);
document.body.appendChild(head);
}
function newPara (para) {
var newP = document.createElement('p');
var newPText = document.createTextNode("text for p" + para);
newP.appendChild(newPText);
var intoH = document.getElementsByTagName('h' + para)[0];
intoH.appendChild(newP);
}
for (i = 1; i <= 6; i++) {
newHeader(i);
}
for (i = 1; i <= 6; i++) {
newPara(i);
}

Search and match CSV file values with javascript

I've uploaded a CSV-file to an HTML page via javascript. The CSV rows are: name and email-address, e.g. rambo,rambo#rambo.com.
How to SEARCH the 'name' from these loaded CSV-file?
Also, one of the data is an email-address and I want to send a mail to that email-address. Is that value retrieved to a variable?
My code to search each elements:
function Search() {
var fileUpload = document.getElementById("fileUpload");
var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.csv|.txt)$/;
if (regex.test(fileUpload.value.toLowerCase())) {
if (typeof (FileReader) != "undefined") {
var reader = new FileReader();
reader.onload = function (e) {
var table = document.createElement("table");
var rows = e.target.result.split("\n");
for(var i = 0; i < rows.length; i++)
{
var row = table.insertRow(-1);
var cells = rows[i].split(",");
for(var j = 0; j < cells.length; j++)
{
var cell = row.insertCell(-1);
// cell.innerHTML = cells[j];
// Here repeated checkboxes:
var radio = document.createElement('input');
radio.type = 'checkbox';
radio.name = 'check';
}
var ser=document.getElementById("texts");
if(cells[i].indexOf(ser))
{
alert("matches");
cell.innerHTML = cells[i];
}
else
{
alert("unmatches");
}
var cell = row.insertCell(-1);
cell.appendChild(radio);
//cell.appendChild(button);
}
var button = document.createElement('button');
button.textContent = 'Send';
cell.appendChild(button);
button.onclick = function(){ alert();};
var dvCSV = document.getElementById("dvCSV");
dvCSV.innerHTML = "";
dvCSV.appendChild(table);
}
reader.readAsText(fileUpload.files[0]);
}
}
}
Ad search: indexOf() is your friend here. This should give you a figure:
var table = $('#your-table'),
searchstring = 'your-searchstring';
searchstring.toLowerCase();
for (var i = 0, cell; cell = table.cells[i]; i++) {
if (cell.indexOf(searchstring)) {
// I don't know what you want to do with the search-results...
// ..but you can do it here.
}
}
Ad email-address: you can add the address to a variable in your CSV-import:
var cells = rows[i].split(","),
address = cells[1];
I'd suggest making an array addresses and fill it each row.

Categories