This question already has answers here:
Javascript:DIV AppendChild
(2 answers)
Closed 4 years ago.
i have a problem with appendChild. in the code below , i am trying to add multiple button elements to the div with looping , but i get only one button . I know how appendChild works . In developers.mozilla it is said , that if element already exists , it is removed from its parent and is set anew . So this is the reason i cant add multiple amount of same elements (button) to the node .
So here is my question , what is the optimal and best way to make it happen ?
function Slide() {
this.currentStep = 0;
this.time = 2000;
this.images = [];
this.images[0] = 'images/image1.jpg';
this.images[1] = 'images/image2.jpg';
this.images[2] = 'images/image3.jpg';
this.images[3] = 'images/image4.jpg';
this.images[4] = 'images/image5.jpg';
let imagesCount = this.images.length;
let indicatorContainer = document.createElement('div');
indicatorContainer.classList.add('slide-indicator');
let buttonIndicator = document.createElement('button');
buttonIndicator.classList.add('button-indicator');
buttonIndicator.setAttribute('type', 'button');
for (let i = 0; i < imagesCount; i+=1) {
indicatorContainer.appendChild(buttonIndicator);
}
document.querySelector('.slide').appendChild(indicatorContainer);
}
Slide.prototype.carousel = function() { // arrow function-ov chi ashxatum ...uxxel
document.querySelector('.image').src = this.images[this.currentStep];
this.currentStep < this.images.length - 1 ? this.currentStep += 1 : this.currentStep = 0;
setTimeout(this.carousel.bind(imageSlide), this.time);
};
const imageSlide = new Slide();
imageSlide.carousel();
<div class="wrapper">
<div class="slide">
<img class="image" src="" width="1000" height="500" alt="image">
</div>
<div class="controls">
<button class="button prev" type="button">
previous
<span class="arrow arrow-prev"></span>
</button>
<button class="button next" type="button">
next
<span class="arrow arrow-next"></span>
</button>
</div>
</div>
In your approach you're assigning the same buttonIndicator in each loop iteration and not creating any new ones. What you have to to is to create new button in each loop iteration to make it work the way you want.
So this should work:
for (let i = 0; i < imagesCount; i+=1) {
let buttonIndicator = document.createElement('button');
buttonIndicator.classList.add('button-indicator');
buttonIndicator.setAttribute('type', 'button');
indicatorContainer.appendChild(buttonIndicator);
}
Also it makes more sense to use const instead of let as you're not reasigning those variables.
Use cloneNode:
indicatorContainer.appendChild(buttonIndicator.cloneNode());
Related
This question already has answers here:
What do querySelectorAll and getElementsBy* methods return?
(12 answers)
Closed 3 months ago.
I have tried the answers given on the similar questions but I really can't do this one and I actually have no idea what I am supposed to do which is why I made this new question. The respective counter is supposed increase by one each time the respective countUp button is clicked. But now, I got NaN in both counter when I click on the first countUp button. Could you please help? Thank you.
const countUp = document.querySelectorAll('.countUp')
const countDown = document.querySelector('.countDown')
const counter = document.querySelectorAll('.num')
let count = counter.textContent
countUp.forEach((countUp) => {
countUp.addEventListener('click', () => {
counter.forEach((countUp) => {
count++
countUp.innerHTML = count
})
})
});
<div class="rating">
<button class="countUp">+</button>
<span class="num">0</span>
<button class="countDown">-</button>
</div>
<div class="rating">
<button class="countUp">+</button>
<span class="num">0</span>
<button class="countDown">-</button>
</div>
You cannot access the relative span using querySelectorAll. It returns a collection
If you delegate and navigate relatively among siblings, you can save a lot of code and headaches
const container = document.getElementById("container");
container.addEventListener('click', (e) => {
const tgt = e.target.closest("button");
if (!tgt) return; // or use e.target and test tgt.matches("button")
const numSpan = tgt.closest(".rating").querySelector(".num");
if (numSpan.matches(".clicked")) return; // already clicked
numSpan.classList.add("clicked");
let num = +numSpan.textContent;
num += tgt.classList.contains("countUp") ? 1 : -1;
numSpan.textContent = num;
});
<div id="container">
<div class="rating">
<button class="countUp">+</button>
<span class="num">1</span>
<button class="countDown">-</button>
</div>
<div class="rating">
<button class="countUp">+</button>
<span class="num">0</span>
<button class="countDown">-</button>
</div>
</div>
I am in the process of learning Javascript and at the moment I'm only using vanilla js to code stuff.
I'm trying to make 2 button (+ and -) to add and subtract a number.
Here's what I have so far:
let value = document.querySelector("#number");
let add = document.querySelector("#add").addEventListener("click", function(value){
add = value++;
document.querySelector("#number").textContent = add;
});
With the above code, when I click my button my p tag changes to NaN. It is 0 form the start.
Goal it to make it 1.
In case you need the HTML code then this is what I have:
<div class="content">
<button id="add">+</button>
<p id="number">0</p>
<button id="sub">-</button>
</div>
You need to set a global var and add and subtract value on that.
You also need to check value is more then zero using ternary operator (if condition) so that the value is always displayed above zero when subtracting
Live Demo
let value = document.querySelector("#number");
//Store value
let valueNumber = 0
//Add value
document.querySelector("#add").addEventListener("click", function(value) {
valueNumber++;
document.querySelector("#number").textContent = valueNumber;
});
//Subtract value
document.querySelector("#sub").addEventListener("click", function(value) {
valueNumber--;
document.querySelector("#number").textContent = valueNumber > 0 ? valueNumber : 0;
});
<div class="content">
<button id="add">+</button>
<p id="number">0</p>
<button id="sub">-</button>
</div>
Even though the answer has been given, I'd like to share mine.
document.querySelector("#add").onclick = function(){
let num = number.innerText;
number.innerText = num/1 + 1;
}
document.querySelector("#sub").onclick = function(){
let num = number.innerText;
if(num > 0){
number.innerText = num/1 - 1;
}
}
<div class="content">
<button id="add">+</button>
<p id="number">0</p>
<button id="sub">-</button>
</div>
Currently I'm trying to create a quiz, right now it displays the first question with 4 answer choices after the start button I am stuck on how to retrieve the answer. The user clicks, check to see if its correct and loop to the next question. I just want to give the user one chance per question and move on regardless if it's correct or not. If their answer is wrong I will remove seconds from the timer. I have the questions, answer choices, and correct answers in arrays.
<div class="card-body">
<p id="header">
You have 75 seconds to complete this asessment.
Every incorrect answer will cost you time.
<br>
</p>
<button id="start-button" class="btn">Start</button>
<div id="start-game" style="visibility: hidden">
<button id="option0" data-index="0"></button><br>
<button id="option1" data-index="1"></button><br>
<button id="option2" data-index="2"></button><br>
<button id="option3" data-index="3"></button><br>
</div>
</div>
<script src="./script.js"></script>
var timerEl = document.getElementById("timer");
var start = document.getElementById("start-button");
var questionEl = document.getElementById("header");
var option0 = document.getElementById("option0");
var option1 = document.getElementById("option1");
var option2 = document.getElementById("option2");
var option3 = document.getElementById("option3");
var intials = document.getElementById("user-initials");
var buttonEl = document.getElementById("start-game");
var totalTime = 75;
var elapsedTime = 0;
var questionNum = 0;
var questions =["The condition in an if/else statement is enclosed with in _______",
"Arrays in JavaScript can be used to store ______",
"Commonly used data types do not include ______",
"String values must be enclosed within _____ when being assigned to variables"];
var answers =[question1= ["Quotes","Curly brackets","Parentheses","Square brackets"],
question2= ["Numbers and strings","Other arrays","Booleans","All of the above"],
question3= ["Strings","Booleans","Alerts","Numbers"],
question4= ["Commas","Curly brackets","quotes","parentheses"],
];
var correctAnswers = [2,3,2,2];
start.addEventListener("click", function(){
timer();
displayQuestion();
start.style.visibility = "hidden";
buttonEl.style.visibility = "visible";
});
function timer(){
var timerInterval = setInterval(function(){
totalTime --;
timerEl.textContent = totalTime;
if(totalTime === 0){
clearInterval(timerInterval);
endQuiz();
return;
}
}, 1000);
}
function newQuiz(){
questionEl.textContent = (questions[0]);
};
function displayQuestion(){
for( var i = 0; i < questions.length ; i++){
questionEl.textContent=(questions[i]);
option0.textContent=(answers[i][0]);
option1.textContent=(answers[i][1]);
option2.textContent=(answers[i][2]);
option3.textContent=(answers[i][3]);
console.log(i);
return;
}
}
Hi I will try to provide an easy solution to your question without using any kind of difficult javascript syntax so here goes..
First in your html file update the option button and add a class property called clickOption(you can change the class name if you want, but be sure to change in other places in script.js as well). The code is shown below.
<button id="option0" class="clickOption" data-index="0"></button><br>
<button id="option1" class="clickOption" data-index="1"></button><br>
<button id="option2" class="clickOption" data-index="2"></button><br>
<button id="option3" class="clickOption" data-index="3"></button><br>
Now in your script.js file add the line of code shown below. I have added inline comments for better understanding
// get all elements with class clickoption i.e all option buttons
var elements = document.getElementsByClassName("clickOption");
//use the below array to track the selected answers
var selectedAnswers = [];
var clickOption = function() {
/** Here I have reached the end of the test and,
I am logging the array of user-selected options.
This array can be compared with correctAnswers array
to determine whether the answer is correct or not **/
if(questionNum >= questions.length) {
console.log(selectedAnswers);
return;
}
/**Get the option value that was clicked.
Here I am using parseInt because,
the data-index attribute value will be in string format,
and the correctAnswers array is in Number format so it is better,
to keep the selectedAnswers array in Number format as it will faciliate
easier data comparison**/
var selectedOption = parseInt(this.getAttribute('data-index'));
// add the selected option to the selectedAnwsers Array
selectedAnswers.push(selectedOption);
/** here I am assuming that you are using the questionNum variable
to track the current question Number **/
questionNum += 1;
/** here I am again checking if I have reached the end of test and
thus log the answers
Instead of logging the answer you can create a function
that compares the result and display it on screen **/
if(questionNum >= questions.length) {
console.log(selectedAnswers);
return;
}
// update the next question text
questionEl.textContent = questions[questionNum];
// update next options
displayQuestion(questionNum);
}
//loop through all the elements with class clickOption
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', clickOption);
}
start.addEventListener("click", function() {
timer();
/** I have updated the displayQuestion call implementation
so that the function is called with a parameter
(here the parameter it is zero) **/
displayQuestion(questionNum);
start.style.visibility = "hidden";
buttonEl.style.visibility = "visible";
});
/**Finally I have updated the display question method
so that it updates the option buttons based on the index parameter **/
function displayQuestion(index){
questionEl.textContent = questions[index];
option0.textContent = answers[index][0];
option1.textContent = answers[index][1];
option2.textContent = answers[index][2];
option3.textContent = answers[index][3];
}
Hope this solution helps you. Happy Coding!
I am trying to change navigation a tag color when the user clicks on the <a> tag. The JS is working fine, except the first time the user clicks on the <a> tag; only in the second time the a tag color changes.
JavaScript:
function toggleNav(pageId){
activeColor();
var href = 'html/' + pageId + '.html';
window.onload = document.getElementById('main').innerHTML =
loadPage(href);
}
function activeColor(){
var header = document.getElementById("allNav");
var btns = header.getElementsByClassName("notActive");
for (var i = 0; i < btns.length; i++) {
var button1 = btns[i];
button1.addEventListener("click" ,
function() {
var current = document.getElementsByClassName(" active");
console.log(current.length);
for (var i = 0; i < current.length + 1; i++) {
current[0].className = current[0].className.replace("
active", "");
}
var myString = this.id;
var stringLength = myString.length;
var lastChar = myString.charAt(stringLength - 1);
if(lastChar == "2"){
var add = document.getElementById(this.id);
var id2Nmae = add.id.slice(0, -1);
var add2 = document.getElementById(id2Nmae);
add.className += " active";
add2.className += " active";
}
else{
var add = document.getElementById(this.id);
var id2Nmae = add.id + "2";
var add2 = document.getElementById(id2Nmae);
add.className += " active";
add2.className += " active";
}
});
}
}
HTML :
<div id="allNav">
<div class="sidebar" id="mySidebar" style="display:block">
<button id="open" onclick="Toggle()">
<a ><i class="fas fa-bars"></i></a>
</button>
<i class="glyphicon glyphicon-screenshot"></i>
<i class="glyphicon glyphicon-exclamation-sign"></i>
<i class="fas fa-burn"></i>
<i class="fas fa-utensils"></i>
<i class="fa fa-line-chart"></i>
<i class="far fa-comments"></i>
<i class="fas fa-bell"></i>
</div>
I succeeded to solve the problem, It was an issue I made by the DOM path not correct.
In the first time the page loads, the default load was the "goals" id by the next JS code:
var href = 'html/goals.html';
window.onload = document.getElementById('main').innerHTML = loadPage(href);
In this why the "addEventListener" needed to load at the first time and only in the second time the function can run.
I changed the default function to:
toggleNav('goals')
I hope I helped if somebody will experience the same issue.
Thanks for the help.
I ran your script and in the console I got
Uncaught TypeError: Cannot read property 'id' of null
(in chrome dev tools) Have you checked the element view (next to console) to see how the javascript is interacting with the HTML?
from looking at the code, the number "2" is for ids that are selected, however, everything ends with the number 2 and it is never actually removed. Is that intentional?
The loop doesn't seem to like "this.id" as it loses the reference (error above).
have you put in alerts to see where the pointer is in the loop?
I need some help with the click event, I'm trying to have an individual counter that is incremented by the click event that I have on the img. I've tried many variations, I want to resolve this without using jQuery.
<script async>
var count = 0;
var clickerCount = document.getElementsByClassName('clicker');
var cat = {
count : 0,
counter: function(){
this.count++;
clickerCount.textContent = "Kitten Click Count :" + this.count;
console.log("counter function working");
console.log(cat.count);
}
};
function modifyNum(){
cat.counter();
console.log("modifyNum function working");
}
</script>
</head>
<body>
<div style="display:inline">
<div>
<img src="http://placekitten.com/200/296" id="cat0" onclick="modifyNum();">
<p id='clicker'>Kitten Click Count :</p>
</div>
<div>
<img src="http://placekitten.com/200/296" id='cat1' onclick="modifyNum();">
<p id='clicker'>Kitten Click Count :</p>
</div>
</div>
For a start, you are using id='clicker' in two places (IDs are supposed to be unique), and then using document.getElementsByClassName, which returns nothing because you used an ID and not a class.
Once you do change it to a class, document.getElementsByClassName will return an array of elements. You'll have to use clickerCount[0] and so on, or loop through the array.
This example should work. I've separated the HTML from the Javascript because it looks clearer for me. You can use it as an example to expand / create your own in your own way.
Hope it help
HTML:
<div style="display:inline">
<div>
<img src="http://placekitten.com/200/296" id="1" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-1">0</span>
</div>
<div>
<img src="http://placekitten.com/200/296" id="2" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-2">0</span>
</div>
</div>
JS:
var imagesCountable = document.getElementsByClassName("countable");
var counters = [];
for (var i = 0; i < imagesCountable.length; i++) {
counters[imagesCountable[i].id] = 0;
imagesCountable[i].onclick = function(e) {
document.getElementById("counter-for-" + e.currentTarget.id)
.innerHTML = ++counters[e.currentTarget.id];
}
}
var imagesCountable = document.getElementsByClassName("countable");
var counters = [];
for (var i = 0; i < imagesCountable.length; i++) {
counters[imagesCountable[i].id] = 0;
imagesCountable[i].onclick = function(e) {
var cElem = document.getElementById("counter-for-" + e.currentTarget.id);
cElem.innerHTML = ++counters[e.currentTarget.id];
}
}
<div style="display:inline">
<div>
<img src="http://placekitten.com/200/296" id="1" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-1">0</span>
</div>
<div>
<img src="http://placekitten.com/200/296" id="2" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-2">0</span>
</div>
</div>
I have solved this problem in this JSFiddle!
If you can hardcode the IDs then it's easier in my point o view to just manipulate things by ID.
<div>
<img src="http://placekitten.com/200/296" id="cat0" onclick="counter(0);">
<p id='clicker0'>Kitten Click Count :</p>
<input type="hidden" id="counter0" value="0">
</div>
function counter(id) {
var cnt = parseInt(document.getElementById("counter" + id).value);
cnt++;
document.getElementById("counter" + id).value = cnt;
document.getElementById('clicker' + id).innerHTML = 'Kitten Click Count :' + cnt;
}
It's not the same approach but I find it easy to understand.
Hope it helps.
Ok, so first off you have two elements with the id of 'clicker'. You probably meant for those to be classes and ids. So when you call modifynum() it cant locate those because the class doesn't exists. Second, your JS is loading before your HTML elements. So when the JS gets to this line:
var clickerCount = document.getElementsByClassName('clicker');
It is going to find nothing, even if you correct the class names. So you want to move your JS to the footer of your HTML document, or wrap the code in a method that is called on pageLoad().
I think that should take care of it. Your object, for the most part, looks correct.