How do you increase a number when a new row is added? - javascript

My Problem
I would like some help understanding how to increase the label const label = document.createElement("label"), which would start at 1 and increase with every new row added.
This section of code is the addEventListener for the button
document.querySelector('button').addEventListener('click', renderRow())
This section of code renders the row when the button is clicked
function renderRow() {
const row = document.createElement('div');
const label = document.createElement("label");
const input1 = document.createElement("input");
input1.type = "number";
const input2 = document.createElement("input");
input2.type = "number";
const result = document.createElement("div");
row.append(label, input1, input2, result);

There are many ways you can achieve this. Here is a small, modified excerpt of your code as an example with some explanation comments.
The basic idea of this approach is to render elements based on a dynamic state which in this case is just a counter that controls how many children are rendered at a given moment. The add and delete buttons control this counter and call the render function to reflect the updated state of the counter in the view.
// define a static starting number if needed
const startingNum = 5;
// define dynamic counter
let counter = 0;
// get ref of parent rows container
const divBox1 = document.querySelector(".fifth-row");
// increase counter when add button is clicked and render rows
document.querySelector('button')
.addEventListener('click', function () {
counter += 1;
renderRows();
});
// decrease counter when any of the delete buttons is clicked and render rows again
divBox1
.addEventListener('click', function (e) {
if (e.target.classList.contains('deleteBtn')) {
counter -= 1;
renderRows();
}
});
// render rows based on the state of the counter
function renderRows() {
// calc total number of rows to render based on current counter value
const total = (startingNum + counter) - startingNum;
// clear container by removing children
divBox1.innerHTML = '';
// render rows
for (let i = 0; i < total; i++) {
addRow(startingNum + i);
}
}
function addRow(rowNumber) {
// create a container for each row
const rowContainer = document.createElement('div');
rowContainer.classList.add('row-container');
divBox1.appendChild(rowContainer);
const labelBox = document.createElement("LABEL");
rowContainer.appendChild(labelBox);
labelBox.classList.add('labelBet');
// set the text content including the dynamic row number
labelBox.textContent = "Bet " + rowNumber;
const inputBox = document.createElement("INPUT");
rowContainer.appendChild(inputBox);
inputBox.classList.add('oddsEntry');
const divBox2 = document.createElement("DIV");
rowContainer.appendChild(divBox2);
divBox2.classList.add('stakePreTotal');
const divBox3 = document.createElement("DIV");
rowContainer.appendChild(divBox3);
divBox3.classList.add('liaDiv');
const btnDel = document.createElement("BUTTON");
btnDel.innerText = 'Delete';
rowContainer.appendChild(btnDel);
btnDel.classList.add('deleteBtn');
}
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
button {
padding: .3rem .5rem;
}
.rows > div.fifth-row > div {
display: flex;
}
<div class="rows">
<div class="fifth-row"></div>
</div>
<button type="button">add row</button>

Related

Scann the value of an span and add an counter in another div when the value is 0 or less

Im trying to scann the value of an span element, by clicking an button. And if the value of the span is 0 the counter in the div is supposed to add one.
Here is a part of the HTML i use:
<span id="result"></span>
<button id="calculateBtn">Calculate</button>
<div id="playerlegs"></div>
I already tried something out with JS but nothing happens and i don't now why and what could also work.
const button = document.querySelector("#calculateBtn");
const spanElement = document.querySelector("#result");
const displayElement = document.querySelector("#playerlegs");
let count = 0;
button.addEventListener("click", function() {
const spanValue = parseInt(spanElement.textContent, 10);
if (spanValue === 0) {
count++;
displayElement.innerHTML = count;
} else if (spanValue < 0) {
displayElement.innerHTML = "Negative number";
}
});

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>

Function not invoking and changing background color on mouseover

I have populated a container with grids and now want to add functionality whereby when your mouse goes over the cells the background colour changes.
So far I have:
let container = document.getElementById("container");
let createGrid = (row, col) => {
for(let i = 0; i < (row * col); i++) {
let cell = document.createElement("div");
cell.className = ("cell");
container.appendChild(cell);
}
}
createGrid(100, 60);
let cells = document.querySelectorAll('container div');
let functionality = () => cells.addEventListener('mouseover', function() {
cells.style.backgroundColor = "red";
}
);
functionality();
You are not correctly targeting the <div> elements in your querySelectorAll. Also, querySelectorAll returns a NodeList object that consists of all the div elements that you queried so you have to loop through each element in the NodeList using a method like forEach() and then apply the style to each element.
Check and run the following Code Snippet for a practical example of the above approach:
let container = document.getElementById("container");
let createGrid = (row, col) => {
for(let i = 0; i < (row * col); i++) {
let cell = document.createElement("div");
cell.className = ("cell");
container.appendChild(cell);
}
}
createGrid(100, 60);
let cells = document.querySelectorAll('#container div');
let functionality = () => cells.forEach(e => e.addEventListener('mouseover', (e) => {
e.target.style.backgroundColor = "red";
}
));
functionality();
.cell {padding: 5px;}
<div id="container"></div>
N.B. Instead of targeting all <div> elements inside #container, you can target all the div elements with the class name "cell" since you have added that class name to each grid element and that would prevent unwanted css changes to other types of <div> elements that you might add to #container in the long run.
If you don't want to do anything else when hovering you can just apply CSS like this:
.cell:hover{
background-color: red;
}
If you want to do this whit JavaScript you need to iterate over the cells and add the listener for each cell:
for(var i=0;i<cells.length;i++){
cells[i].addEventListener('mouseover', function(event) {
event.target.style.backgroundColor = "red";
});
The color on hovering will not stay, if you do it with JavaScript the red background color will stay after leaving the cell.

Javascript Pagination Issue

I'm trying to make a simple Javascript pagination function, but I'm having this issue where instead of iterating through the array, it keeps adding new list items to the innerhtml.
I have tried creating an element and appending it to the DOM.
I have tried using if/else statements to display the list items I
want.
<body>
<div class='result'></div>
<button class="add">+</button>
<script src='pretty.js'></script>
</body>
let dogs = [
'goldendoodle',
'poodle',
'afghan hound',
'golden retriever',
'labrador',
'chihuahua',
'pitbull',
'german shepherd',
'greyhound',
'bull terrier'
]
let high = 1;
let low = 0;
let result = document.querySelector('.result');
let add = document.querySelector('.add');
function Pagination(low,high) {
for(var i = 0 ; i < dogs.length;i++) {
let answer = document.createElement('div');
answer.classList.add('dogs-dom');
answer.innerHTML = dogs[i];
result.appendChild(answer);
if(i >= low && i < high) {
answer.style.display ='block';
}
if(i < low || i > high) {
answer.style.display ='none';
}
}
}
Pagination(low,high);
add.addEventListener('click', () => {
low += 2;
high += 2;
Pagination(low,high);
});
When I click the button, I want the next two array items to appear and replace the last two shown.
To use the approach you've outlined above you'll need to clear the innerHtml of the result element before appending new children. At the top of your Pagination function try result.innerHtml = '';.
That said if you are using a hide/show approach to paginate the list it would be more efficient to create the dom elements only once and modify the style.display property of each instead of clearing out the result and re-creating all of the answer divs on every click.
Your Pagination function only adds elements to the dom each time it is called.
You can either remove the existing elements every time Pagination is called, and render only those that should be displayed, e.g.:
function Pagination(low,high) {
result.innerHTML = ''; // remove all children of result
// only render the children which should be visible
for(var i = low ; i < high;i++) {
let answer = document.createElement('div');
answer.classList.add('dogs-dom');
answer.innerHTML = dogs[i];
result.appendChild(answer);
}
}
Or you can use display: block; / display: none. (Will not scale very well with large lists)
function Pagination(low,high) {
// only append all dogs once
if(result.childElementCount === 0) {
for(var i = 0; i < dogs.length;i++) {
let answer = document.createElement('div');
answer.classList.add('dogs-dom');
answer.style.display ='none';
answer.innerHTML = dogs[i];
result.appendChild(answer);
}
}
// toggle display: none / block for each element
for(var i = 0; i < dogs.length;i++) {
if(i >= low && i < high)
answer.style.display ='block';
else
answer.style.display ='none';
}
}
As a bonus, heres a reusable pagination class example:
function Pagination(container, items) {
this.container = container;
this.result = container.querySelector('.result');
this.prevBtn = container.querySelector('.prev');
this.nextBtn = container.querySelector('.next');
this.items = items;
this.offset = 0;
this.limit = 5;
this.updateDom();
this.prevBtn.onclick = this.prevPage.bind(this);
this.nextBtn.onclick = this.nextPage.bind(this);
}
Pagination.prototype.nextPage = function() {
if((this.offset + this.limit) < this.items.length)
this.offset += this.limit;
this.updateDom();
};
Pagination.prototype.prevPage = function() {
if(this.offset >= this.limit)
this.offset -= this.limit;
this.updateDom();
};
Pagination.prototype.updateDom = function() {
this.result.innerHTML = '';
let stop = Math.min(this.offset + this.limit, this.items.length);
for(let i = this.offset; i < stop; i++) {
let el = document.createElement("div");
el.appendChild(document.createTextNode(this.items[i]));
this.result.appendChild(el);
}
let hasPrev = this.offset > 0;
if(hasPrev)
this.prevBtn.classList.remove('hide');
else
this.prevBtn.classList.add('hide');
let hasNext = (this.offset + this.limit) < this.items.length;
if(hasNext)
this.nextBtn.classList.remove('hide');
else
this.nextBtn.classList.add('hide');
};
let items = [];
for (let i = 1; i <= 50; i++)
items.push(`Item ${i}`);
let pagination = new Pagination(document.querySelector(".paginate"), items);
// You can also programatically switch to the next / prev page:
// pagination.nextPage();
// pagination.prevPage();
.hide { visibility: hidden; }
<div class="paginate">
<div class="result"></div>
<button class="prev">PREV</button>
<button class="next">NEXT</button>
</div>
Maybe this is along the lines of what you want to do?
It tracks only a globalIndex (which would be like like your 'low' variable).
The showNextTwoItems function:
- Notes the indexes where we should start and end
- Clears the container div
- Enters a while loop that appends items and increments the current index
- Updates the globalIndex when enough items have been added
let dogs = [ 'goldendoodle', 'poodle', 'afghan hound', 'golden retriever', 'labrador', 'chihuahua', 'pitbull', 'german shepherd', 'greyhound', 'bull terrier' ],
containerDiv = document.querySelector('.result'),
addBtn = document.querySelector('.add'),
globalIndex = 0; // Tracks where we left off (starts at zero)
const NUMBER_TO_SHOW = 2;
addBtn.addEventListener("click", showNextTwoItems); // Calls function on click
function showNextTwoItems(){
let numberToShow = NUMBER_TO_SHOW, // In case we ever want to change numberToShow
currentIndex = globalIndex, // Gets local copy of globalIndex (always < dogs.length)
// Lets us stop looping when we've shown enough or reach the end of the array
stopBeforeIndex = Math.min(currentIndex + numberToShow, dogs.length);
containerDiv.innerHTML = ""; // Clears div
while(currentIndex < stopBeforeIndex){
// Creates and appends a text node with the next dog
const newItem = document.createTextNode(dogs[currentIndex]);
containerDiv.appendChild(newItem);
// Creates and appends a line break
const lineBreak = document.createElement("BR");
containerDiv.appendChild(lineBreak);
// Moves on to the next index
currentIndex++;
}
// Updates global index (making sure it is not too big for the array)
globalIndex = currentIndex < dogs.length ? currentIndex : 0;
}
<button class="add">+</button>
<div class='result'></div>

Adding ledger totals in multiple TDs

This code generates a ledger. I narrowed it down to the minimum. By clicking a plus sign it adds an additional row to the ledger.
I'm looking to add each total of the variable newAmount and locate its updated total in a TD to the right of each row. I created newAmount.id = "mainAmount"; to create unique IDs thinking this would help.
var mainNumber = 0;
function addElement()
{
//add a number for each row
mainNumber++;
//create each row, id each slot, and add it where it goes
newDiv = document.createElement("div");
newDiv.id = "main";
newTable = document.createElement("table");
newTable.id = "mainTable";
newDiv.appendChild(newTable);
newTr = document.createElement("tr")
newTr.id = (mainNumber);
newTr.className = "mainRow";
newTable.appendChild(newTr);
newAmount = document.createElement("td");
newAmount.id = "mainAmount";
newAmount.className = (mainNumber);
newPlus = document.createElement("td");
newPlus.id = "mainPlus";
newTotalTable = document.createElement("table");
newDiv.appendChild(newTotalTable);
newTotalTable.id = "mainTotalTable";
newTotalTr = document.createElement("tr");
newTotalTable.appendChild(newTotalTr);
newTotalTr.id = "mainTotalTr";
newTotalTd = document.createElement("td");
newTotalTd.id = "mainTotalTd" + (mainNumber);
newTr.appendChild(newAmount);
newTotalTr.appendChild(newTotalTd);
//whats default inside of each slot
newAmount.innerHTML = '<form name="formAmount"><textarea name="textAmount" size="25" onfocus="wait();" id="amount' + (mainNumber) + '">0</textarea>';
newTr.appendChild(newPlus);
//click this to add a row
newPlus.innerHTML = '<img src="images/plus.png">';
// add the newly created element and it's content into the DOM
my_div = document.getElementById("mainAnchor");
document.body.insertBefore(newDiv, my_div);
}
//doesn't work...trying to hover over any row and show var idName in console
function trHover(){
$('tr').hover(function() {
var idName = $('tr'+'#'+(mainNumber)).attr('id');
console.log(idName);
});
}
//when you focus on amount box, this is activated, which adds attribute onblur and stars addTotal
function wait(){
var blurred = $(this).attr("onblur");
blurred = addTotal();
}
//adds total and displays it in td to the right
function addTotal(){
var y = 1;
var sum = 0;
var input;
while( ( input = document.getElementById( 'amount'+y ) ) ) {
sum += parseInt( input.value );
++y;
console.log(sum);
$("#mainTotalTd1").text(sum);
}
}
Rather than adding a single row, it looks like clicking the plus sign adds a div and two tables, so I'm not sure what you are going for there. I can fix the hover function, though:
$('tr').hover(function() {
var idName = $(this).attr('id'); // 'this' is the element being hovered
console.log(idName);
});

Categories

Resources