Creating buttons with JS that keeps variable upon creation - javascript

I'm creating a HTML table by using JavaScript.
I want add button to the cell with index 5 on each row.
The console.log(i) before the btn.onclick... writes the value of i but when the different buttons are pressed all the outputs are the same and are always 10.
I guess this is because the variable in the function gets updated.
How do you make it so that the button on each row outputs the value of i when the button is "created"
Take a look at my code
var tableRef = document.getElementById("my_table").getElementsByTagName("tbody")[0];
var i;
for (i = 0; i < 10; i++) {
var newRow = tableRef.
newCell = newRow.insertCell(5);
btn = document.createElement('input');
btn.type = "button";
btn.className = "btn";
btn.value = "My button";
console.log(i);
btn.onclick = function() {
console.log(i);
};
newCell.appendChild(btn);
}

Lets follow the JavaScript execution step by step.
You get access to the table
You create the loop which iterates from 0 to 9 (10 steps)
On each step you create the button and assign listener function to the onclick event.
The listener function keep reference to the i variable.
When you loop reach the end
All your elements have rendered to the screen and buttons are available
At this moment i variable is equal to 9.
You click a button.
After clicking the button your function go to the i variable and fetch the value.
The i value is equal to 9 and therefore it prints 9.
To fix this you can move var i; to the loop statement and replace var with let.
See example below
var tableRef = document.getElementById("my_table").getElementsByTagName("tbody")[0];
for (let i = 0; i < 10; i++) { // Use let here
var newRow = tableRef.
newCell = newRow.insertCell(5);
btn = document.createElement('input');
btn.type = "button";
btn.className = "btn";
btn.value = "My button";
console.log(i);
btn.onclick = function() {
console.log(i);
};
newCell.appendChild(btn);
}
For more information you can read the article
I hope this helps you

Related

using the DOM to output different sized pyramids to a webpage

Continuing from above, whenever the button is clicked, the pyramid of whatever height the user input into the text box does print. But, if you click the button again, it prints a whole new pyramid without removing the old one. What I need to know is how to add a line of code to the beginning of the drawPyramid Function that clears the old content before creating a new Pyramid in Vanilla Javascript, HTML, and/or CSS. I do have a lot of notes written for the code but that's mostly for me because it's just the way that I learn best is to overexplain everything that's happening in the code which I also would appreciate in responses if possible.
Here is the JavaScript portion of what I have:
function determineHeightAndThenDrawPyramid() {
//Sets height == to input value typed by user
let height = document.getElementById("height").value;
//Creates btn that 'onclick' calls the printPyramid function
let btn = document.getElementById("MyBtn").addEventListener("click", printPyramid(height));
}
//Building the pyramid
function printPyramid(height) {
//Figure out how to clear the old output??
console.clear();
let numBricks = 0;
let numSpaces = 0;
for (let row = 0; row < height; row++) {
let layer = "";
//figure out number of bricks and spaces
numBricks = row + 2;
numSpaces = height - row - 1;
for (let i = 0; i < numSpaces; i++) {
layer += ".";
}
for (let i = 0; i < numBricks; i++) {
layer += "#";
}
//Prints layer to console
console.log(layer);
//Prints layer to DOM
//Creates new paragraph element
let para = document.createElement("p");
//Creates a text node from layer variable
let rowStr = document.createTextNode(layer);
//Para becomes parent of rowStr
para.appendChild(rowStr);
//Grabs pyramid ID from HTML
let element = document.getElementById("pyramid");
//Element becomes parent of para
element.appendChild(para);
//Summation:
//element/para/rowStr.
//Element == ID of pyramid.
//Para(New paragraph tag) == rowStr.
//rowStr == layer variable == string to build pyramid
}
}
<input id="height" />
<button id="MyBtn">Go!</button>
<div id="pyramid">--</div>
Thank you for any advice!
There are some important errors:
When you set the event listener, you need to use a function callback, not a called function
Use append instead of appendChild
You need to get the height just after clicking the button
Then, to remove the previous pyramid before appending the new one, just remove the contents of its container.
Finally (or, better said, initially), the function assigning the event listener needs to be called only once.
Advice: use const instead of let whenever possible.
The code snippet works.
function assignListener() {
//Sets height to the input DOM element
const height = document.getElementById("height");
// Save the button DOM element into btn,
// not the result from addEventListener
const btn = document.getElementById("MyBtn");
// Use a lambda callback which will call printPyramid
// with the current value (when user clicks) of the input `height`
btn.addEventListener("click", () => printPyramid(height.value));
}
//Building the pyramid
function printPyramid(height) {
//Figure out how to clear the old output??
console.clear();
let numBricks = 0;
let numSpaces = 0;
// ==> Find and empty pyramid before starting
//Grabs pyramid ID from HTML
const element = document.getElementById("pyramid");
// ==> Empty `element` contents
element.innerHTML = '';
for (let row = 0; row < height; row++) {
let layer = "";
//figure out number of bricks and spaces
numBricks = row + 2;
numSpaces = height - row - 1;
for (let i = 0; i < numSpaces; i++) {
layer += ".";
}
for (let i = 0; i < numBricks; i++) {
layer += "#";
}
//Prints layer to console
console.log(layer);
//Prints layer to DOM
//Creates new paragraph element
const para = document.createElement("p");
// Creates a text node from layer variable
const rowStr = document.createTextNode(layer);
// Para becomes parent of rowStr
// ==> Use `append` instead of `appendChild`
para.append(rowStr);
// Element becomes parent only of para
// ==> Use `append` instead of `appendChild`
element.append(para);
//Summation:
//element/para/rowStr.
//Element == ID of pyramid.
//Para(New paragraph tag) == rowStr.
//rowStr == layer variable == string to build pyramid
}
}
// ==> Call the event listener assigner only once
assignListener();
<input id="height" />
<button id="MyBtn">Go!</button>
<div id="pyramid">--</div>

How to exchange counter after delete field using plain javascript

I'm new in javascript. i have a JS function that add and remove input fields. its working fine with my JS function. But I want when delete a field its Id looks like:
I have
no. 1
no. 2
no. 3
After Delete 2:
no. 1
no. 2
already i got this answer:
Reset JavaScript Counter after Deleting a field
But i want it with plain javascript. Can anyone help?
<script>
var count = 1;
function add_new(){
count++;
var div1 = document.createElement('div');
div1.id = count;
var delLink = '<button type="button" onclick="deleteLink('+count+')" class="btn btn-primary">Delete</button>';
div1.innerHTML = document.getElementById('add_link1').innerHTML+delLink;
document.getElementById('add_link').appendChild(div1);
document.getElementById("input_link1").id = count;
document.getElementById("input_link2").id = count;
document.getElementById("input_link3").id = count;
}
function deleteLink(eleId){
var ele = document.getElementById(eleId);
var par = document.getElementById('add_link');
par.removeChild(ele);
}
</script>
After deleting an element call the following function to reset Id of existing elements and also reduce the count.
function reset_counter(deletedCount) {
for (var impactedElementId = deletedCount + 1; impactedElementId < count; impactedElementId++) {
var currentElement = document.getElementById(impactedElementId);
currentElement.id = impactedElementId - 1;
var button = currentElement.firstChild;
button.innerHTML = 'Delete ' + currentElement.id;
button.setAttribute('onclick', 'deleteLink(' + currentElement.id + ')');
}
count--;
}
The full code is available here: AddDeleteElements Sample Code

document.getElementById class applies to the whole array instead of each element

<p><span id="sr" class="btn">elements of the array</span></p>
for(var i = 0; i < myarray.length; i++)
{
var sr = (function(val) {
btn = document.createElement('button');
btn.data = val;
btn.innerHTML = val;
btn.addEventListener('click', checkAnswer);
document.body.appendChild(btn);
return btn.data = val;
})//(myarray[i]);
document.getElementById("sr").innerHTML = myarray;
}
With this code the elements of the array appear in the html span. I want each element to appear as a button, as defined in the class "btn". However, the class changes the style of the array as a whole, not as single buttons. What is the correct way to define the style of each button?
I tried document.getElementById("sr").innerHTML = myarray.class="btn";. It does not work. Definitely not the correct syntax. Any idea?
Is this what you want to achieve?
let container = document.getElementById('sr');
let array = ['element1', 'element2', 'element3'];
function checkAnswer () {
console.log('Selected answer: ', this.textContent);
}
for (let i = 0; i < array.length; i++) {
let button = document.createElement('button');
button.textContent = array[i];
button.addEventListener('click', checkAnswer);
container.appendChild(button);
}
<p><span id="sr" class="btn"></span></p>
If I understand you correctly, you want to add btn class to your dynamically created buttons with myarray elements.
What is the correct way to define the style of each button?
I tried document.getElementById("sr").innerHTML = myarray.class="btn";
You can use element.classList.add('your-class');
var myarray = ["Array", "elements"]; //let's say
for (var i = 0; i < myarray.length; i++) {
var sr = (function(val) {
btn = document.createElement('button');
btn.data = val;
btn.innerHTML = val;
btn.classList.add("btn")
btn.addEventListener('click', checkAnswer);
document.body.appendChild(btn);
return btn.data = val;
})(myarray[i]);
//document.getElementById("sr").innerHTML = myarray;//I don't know why this line here?
}
function checkAnswer(e){
}
Use Element.dataset instead of creating a .data property. Pass i to IIFE. If you are trying to display the array myarray as .innerHTML of #sr, concatenate "[" to beginning and "]" to end of myarray setting at .innerHTML, as .innerHTML casts Array to String.
If you are trying to append created element to #sr, do not append element to document.body, but #sr.
function checkAnswer() {
console.log(this.dataset.value)
}
var myarray = [1, 2, 3];
for (var i = 0; i < myarray.length; i++) {
(function(val) {
var btn = document.createElement('button');
btn.dataset.value = val;
btn.className = "btn"; // set `btn` `.className` to `"btn"`
btn.innerHTML = val;
btn.addEventListener('click', checkAnswer);
document.body.appendChild(btn);
// document.getElementById("sr").appendChild(btn);
})(i);
}
document.getElementById("sr").innerHTML = "[" + myarray + "]";
<p><span id="sr" class="btn">elements of the array</span></p>

how to set onclick attribute in a loop

I am building a table with text in the first column and buttons that do stuff in the second column. Here is the complete .js file:
var table = document.createElement("table");
var tableBody = document.createElement("tbody");
for(i = 0; i < array.length; i++) {
var row = table.insertRow(i);
var cell = row.insertCell(0);
cell.innerHTML = text[i];
var cell = row.insertCell(1);
var cellElement = document.createElement("input");
cellElement.setAttribute("id", ID[i]);
cellElement.setAttribute("type", "button");
cellElement.setAttribute("value", "button");
/////cellElement.onclick =
/////function(){ doThisThing(i,ID[i]); } );
cell.appendChild(cellElement);
row.appendChild(cell);
}
table.appendChild(tableBody);
document.body.appendChild(table);
Everything works except for the cellEllement.onclick = function(){}; The onlick() function does not set. I have tried variations on this:
cellElement.setAttribute("onclick",doThisThing(i,ID[i]));
How to I set the button onclick attribute when looping through to create a table?
You're using a reference to the i variable inside your function which will continue to change with the loop, and won't hold the value of i that it has when you go through that iteration of the loop. You need to hold on to the current value of i, probably by wrapping your callback in another function:
cellElement.onclick = (function(currI) {
return function() { doThisThing(currI, ID[currI]); };
})(i);
You could also use bind to make things simpler:
cellElement.onclick = doThisThing.bind(null, i, ID[i]);

issue in removing radio buttons using javascript in IE

I have a implementation where I am creating radio buttons dynamically, actually all the fields and values are dependent on each other like parent- child -grand child and so on. I am able to remove button but in Firefox using innerHtml but in IE it didn't worked. For IE, I got a diffrent code but that also doesn't worked properly below I am pasting code that generates it and removes it.
var idToUpdate = "radioID";
var nameToUpdate = "radioName";
var labelToUpdate = "labelText";
var tbody = document.createElement('tbody');
var row = document.createElement("tr")
var data1 = document.createElement("td")
var newRadio = document.createElement("input");
newRadio.type = "radio";
newRadio.id = idToUpdate;
newRadio.name = nameToUpdate;
newRadio.value = labelToUpdate;
if (defUpdater == 1)
newRadio.setAttribute('checked', 'checked');
newRadio.setAttribute("onclick", "javascript:dependentFieldsValue('" + idToUpdate + "');");
var data11 = document.createElement("td")
var newLabel = document.createElement("label");
newLabel.htmlFor = idToUpdate;
newLabel.id = idToUpdate;
newLabel.appendChild(document.createTextNode(labelToUpdate));
tbody.appendChild(row);
row.appendChild(data1);
data1.appendChild(newRadio);
row.appendChild(data11);
data11.appendChild(newLabel);
Node1.appendChild(row);
defUpdater = 0;
For loop in last is used for removing radio, we just get htmlelemnt using table ID and set the innerHTML to="".
for (var i = 0; i < len; i++) {
var node = documnet.getElemtsById("tableID"); // every button group have table and table is havin id.
Node.childNodes[i].innerHTML = ""; /// works for firefox// works fine
//Node.childNodes[i].Node.removeChild(Node.childNodes[i]);// works for IE but not properly
}
Please suggest.
I would use this construction:
var table = documnet.getElemtsById("tableID");
for (var i = 0; i < len; i++) {
var tr = table.childNodes[i];
tr.parentNode.removeChild(tr);
}

Categories

Resources