I am new to JavaScript and would like to know how I can create multiple divs dynamically with the same class name. I have the following code but it only creates one instance of the div.
<div id="wrapper">
<div id="container">
<div id="board">
<script>
var board = document.createElement('div');
board.className = "blah";
for(x=0; x<9;x++) {
document.getElementById('board').appendChild(board);
}
</script>
</div>
</div>
</div>
Right now, you're creating the element outside the loop, and appending that element to the DOM...again and again.
What you want to do is create a new element during every iteration of the loop. To do that, move the part where you create the new div inside the loop:
for(x=0; x<9;x++) {
var board = document.createElement('div');
board.className = "blah";
document.getElementById('board').appendChild(board);
}
Now, every time the loop runs, you'll create a new element, and append that element to the element with ID #board.
It's worth pointing out that the variable you created (board) now only has scope within this loop. That means that once the loop is done, you'll need to find a different way to access the new elements, if you need to modify them.
Only a single element is created.
<script>
var board = document.createElement('div');
board.className = "blah";
for(x=0; x<9;x++) {
document.getElementById('board').appendChild(board);
}
</script>
Should be written as:
<script>
for(x=0; x<9;x++) {
var board = document.createElement('div');
board.className = "blah";
document.getElementById('board').appendChild(board);
}
</script>
Others did answer the question in a nutshell; here is one approach which addresses some issues that are present in the your and proposed code snippets, and maybe gives your some insight for further exploration. I hope it helps :)
To extend a script a little bit, this solution creates every element by using function createDiv, and references to individual divs are stored in an array, so you can modify the content of each div by modifying array elements, which are referring to DOM elements. (in this example, I modify 6th div for demonstration sake)
Notes:
All of your code is thrown in a global object, it's good
practice to encapsulate your code, here in immediately invoked
anonymous function.
x would be thrown in a global object even if encapsulated, you need
always to declare your variables with a var keyword. Here I declare
all vars needed upfront in one statement, which is also a good
practice;
It is convention to use "i" for loop iterator variable.
Avoid "magic numbers" (9), rather create a variable that will
describe what you do in your code. It is good if the code describes what
it does.
Also in this example, we avoid declaring "board" on each loop
iteration (the element where your divs get appended.)
Test your code in JSLint - great tool to validate your scripts.
(this will pass the test, given that you set indentation to 2.
"use strict" - read here.
/*jslint browser:true */
(function () {
"use strict";
function createDiv() {
var boardDiv = document.createElement("div");
boardDiv.className = "new-div";
boardDiv.innerText = "I am new DIV";
return boardDiv;
}
function createAndModifyDivs() {
var board = document.getElementById("board"),
myDivs = [],
i = 0,
numOfDivs = 9;
for (i; i < numOfDivs; i += 1) {
myDivs.push(createDiv());
board.appendChild(myDivs[i]);
}
myDivs[5].className = "modified-div";
myDivs[5].innerText = "I'm modified DIV";
}
createAndModifyDivs();
}());
.new-div {
color: gray;
}
.modified-div {
color: red;
}
<!DOCTYPE html>
<html>
<head>
<title>Inserting Divs</title>
</head>
<body>
<div id="wrapper">
<div id="container">
<div id="board">
</div>
</div>
</div>
</body>
</html>
Related
I am trying to make a correct and incorrect question counter that shows groups of 4.
If I click on the first correct answer the counter works correctly and increases as I click, but it does not work with the second correct answer. The same happens with the wrong answers
This is the codes that I use, anyone could help me? Thx
HTML CODE:
¿Which of the following operations results in 8?
<input class="solucioncorrecta" value="6+2">
<input class="solucioncorrecta" value="7+1">
<input class="solucionincorrecta" value="1+1">
<input class="solucionincorrecta" value="2+2">
And the JS CODE:
<!-- CONTADOR FALLOS TEST -->
<script type="text/javascript">
var root = document.querySelector('.solucionincorrecta');
root.onclick = function() {
var elem = document.getElementById('contadorfallos');
elem.innerHTML = +elem.innerText + 1;
};
</script>
<!-- CONTADOR FALLOS TEST -->
<!-- CONTADOR ACIERTOS TEST -->
<script type="text/javascript">
var root = document.querySelector('.solucioncorrecta');
root.onclick = function() {
var elem = document.getElementById('contadoraciertos');
elem.innerHTML = +elem.innerText + 1;
};
</script>
The issue is that you are using document.querySelector() and not document.querySelectorAll()
document.querySelector() Returns the first match
document.querySelectorAll() Returns all matches
As a result, you are only setting an onclick property on the first .correcta and .incorrecta elements, not all of them.
To set this on all of them, you need to do two things:
You need use document.querySelectorAll() instead of document.querySelector(). This returns a list (specifically, a NodeList) of matching elements.
Loop over the items in your list, and attach onclick handlers to each of them. There are many ways to loop over a NodeList, listed here.
Here is an example:
// get all incorrect elements
var incorrectElements = document.querySelectorAll('.incorrecta');
// loop over each elements
for (var element of incorrectElements) {
// add an onclick
element.onclick = incorrectClickHandler
}
// this is the function being called by onclick
function incorrectClickHandler() {
score.innerText = parseInt(score.innerText) - 1;
}
It would be better if you upload your full codes. But anyway I write you some notes that probably answer your question.
-dont use the same name (root) for your .correcta and .incorrecta
-in your second <script>, you didnt defined button as an object . So browser cant understand it.
I have an image (SVG) of a human body. I would like to use JavaScript so that when I click a particular area (say, the lower leg) then all of the elements with the class "lower-leg" (even if not clicked) have their color changed -- this makes it much easier for the user.
Here is the JavaScript I currently have:
function changeclassstyle() {
var c = document.getElementsByClassName("lower-leg");
for (var i=0; i<c.length; i++) {
c[i].style.fill = "red";
}
}
The problem with this code is that it is only generalized for "lower-leg". I may have over a dozen classes I would like this to work for and don't think it is efficient to write 12 functions with the only change being the class name. Is there a way to grab what class was selected and then input that in the function?
--
Additionally, I would love to figure out how, once that section of the body is selected, I can store the class name. I would, in the end, want to store the selection, along with other inputted information in a database. But, this may be for a future question unless someone can help!
Here's how I would do it (tested on a couple of div's).
What we're doing is passing the event object to the event handler (your changeclassstyle() function). It then uses the class of the clicked-on item (the event target's class) and changes everything else on that page with that same class name to use your new desired CSS style.
function changeclassstyle(e) {
// Get all items that have the same class as the item that was clicked
var limbs = document.getElementsByClassName(e.target.className); // for div's and the like
// var limbs = document.getElementsByClassName(e.target.className.baseVal); // turns out this is needed for SVG items
// "limbs" is an HTMLCollection, not an array, so functions like .foreach won't work; C-style for-loops or modern for/let/of loops are better
for (let item of limbs) {
item.style.backgroundColor = 'red';
// item.style.fill = 'red'; // This is probably what you need for your SVG items
}
// You could still use your C-style for loop if needed/wanted
/*
for (var i=0; i<limbs.length; i++) {
limbs[i].style.fill = "red";
}
*/
}
The onchange call looks like this (using my div as the example):
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
The whole example with simple div's.
<html>
<head><title>stuff</title></head>
<body>
<script type="text/javascript">
function changeclassstyle(e) {
// For debugging. You may want to expand 'e' here in your browser's debug tools if you're not seeing the values you need/want
console.log(e)
var limbs = document.getElementsByClassName(e.target.className.baseVal);
for (let item of limbs) {
item.style.backgroundColor = 'red';
}
}
</script>
<style type="text/css">
div {
height: 100px;
width: 100px;
background-color: 'white';
border: 1px solid black;
}
</style>
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
</body>
</html>
You can use parameters in function where you pass class and color like below
function changeStyle(cls,clr) {
let elems = document.getElementsByClassName(cls);
if(!elems) return;
for (let elem of elems) {
elem.style.color = clr;
}
}
As per the iteration of many classes like i said you can store classes in array and iterate each of them.
let classes = ['one','two','three','four'];
classes.forEach(function (cls) {
changeStyle(cls,"red");
});
You can play with fiddle here if you want to test/experiment: https://jsfiddle.net/thrL5uqw/8/
Note: Change style property as you wish, For now i have used color for demo
I'm a bit late to the party, but here's my take on the problem.
Like the others told you, you'll need to use an additional parameter to your function to specify the class you want to modify your elements (or try to figure out the class from the clicked element), therefore you should have something like that:
/**
* This function will handle the click event on one of the part of the SVG.
* #param {string} lClass This the class of the element to modify
*/
function handleClick(lClass) {
for (let e of document.getElementsByClassName(lClass)) {
// Here you can do all the changes you need on the SVG element.
e.style.fill = "red";
}
}
And when it comes to the event binding, you could do like the other suggested and add the onclick event binding propery on the HTML Element, or you could bind it in you JS with the addEventListener function (that way you don't have to repeat the onclick property on each of your SVG elements).
// For each element of all the listed class, bind the "click" event to the handleClick function
const listenClass = [/*List of your classes*/];
for (let l of listenClass) {
for (let e of document.getElementsByClassName(l)) {
e.addEventListener('click', handleClick.bind(this, l));
}
}
Demo: https://plnkr.co/edit/gay2yBaVi5QD868fsTa6?p=preview
I hope it helped.
Bit of a noob here! I'm working in pure javascript with the assistance of HTML and CSS, no engine. I'm trying to move a displayed tank sprite composed of 3 parts: tracks, chassis and a turret.
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset="UTF-8">
<link rel='stylesheet' href='.css'>
<div class='tank' id='tracks'></div>
<div class='tank' id='chasis'></div>
<div class='tank' id='turret'></div>
</head>
<body>
<script src='.js'></script>
</body>
</html>
Here I created the three div elements with their unique id for the tracks, chassis and turret. They all share the common class tank.
.tank {
height: 31px;
width: 31px;
position: absolute;
}
#tracks {
background: url("tracks.png");
}
#chasis {
background: url("chasis.png");
}
#turret {
background: url("turret.png");
}
In my CSS code, I attributed all the properties that the 3 components share to their class, so they share the same size and position. Since each of the three elements has a unique image that cannot be shared, I attributed it to each element by id.
var tracks = document.getElementById('tracks');
var chasis = document.getElementById('chasis');
var turret = document.getElementById('turret');
tracks.style.top = '167px';
chasis.style.top = '167px';
turret.style.top = '167px';
This code has done the trick in the sense that it has successfully moved each component down by 167px but I want to avoid rewriting all that every time I want to move the tank by its components.
var tank = document.getElementsByClassName('tank');
tank.style.top = '167px';
So instead, I tried to move the entire tank by class but it didn't work. What am I doing wrong?
Thanks!
<div class="tank">
<div id='tracks'></div>
<div id='chasis'></div>
<div id='turret'></div>
</div>
Can you just try this? So you have TANK which has all the parts inside now.
getElementsByClassName, it returns Node list in Object format. So you can not directly apply style on it. You need to traverse the list using array functions. To get array list you can use querySelectorAll.
const tanks = document.querySelectorAll('.tank');
tanks.forEach(function(tank, index){
tank.style.marginTop = '167px';
});
<div class="tank">1</div>
<div class="tank">2</div>
try putting the divs in the body section and your js in the head section.
also add a [0] to the class as follows,
var tank = document.getElementsByClassName('tank')[0];
edited cause i realised they were not in a div with tank class as suggested by Nex
Ok, I think I found an alternate way to achieve this:
Leave the html and css as they were.
var tracks = document.getElementById('tracks');
var chasis = document.getElementById('chasis');
var turret = document.getElementById('turret');
var tank = [tracks, chasis, turret];
for (var i = 0; i < tank.length; i++) {
tank[i].style.top = '167px';
}
Scrap the js and throw in the above.
Call the elements by their ids and create an array tank to contain them. Then loop through the array while the tank.length (which is 3) is greater than i, move the tank elements by 167px. Since i can only be 0, 1 and 2, the 3 elements (labelled 0, 1 and 2) are moved.
Later if you need to access the singular elements you can call them by their ids or find them in the tank array like so: tank[0], tank[1] or tank[2].
I make a button in HTML, and I want it to call function in javascript:
index.html
<body onLoad="setGameAreaBounds()" onResize="setGameAreaBounds()">
<div id="scoreLabel">Score: 0 </div>
<!--div Group-->
<div>
<p id="pageTitle">Button Chaser</p>
<input type="button" id="startButton" onClick="start()" value="Start"/>
</div>
<!--The following: gameArea and dot is grouped together-->
<div id="gameArea">
<button id="dot" onClick="detectHit()"></button>
</div>
</body>
buttonChaser.js
function detectHit() {
//Increase the var score
}
function setGameAreaBounds() {
//Setting the size of GameBoard/Window
}
function moveDot() {
//randomly move the button(id: dot) within the GameBoard/window
}
function start() {
alert("sometext");
moveDot();
}
The code runs fine if I put moveDot(); function inside setGameAreaBounds();
However, it seems like the button(id: startButton) never connects to function start();
What did I do wrong?
Try moving your functions inside your onLoad function and link them back up to the global scope:
var score = 0;
var aWidth;
var aHeight;
var timer;
var that = this;
function setGameAreaBounds() {
//Setting the size of GameBoard/Window
that.moveDot = function () {
//randomly move the button(id: dot) within the GameBoard/window
}
that.detectHit = function() {
//Increase the var score
}
that.start = _start; // link desired name to reference to existing function
}
function() _start {
alert("sometext");
moveDot();
}
Basically, your html functions are accessing functions defined in the global scope after the dom elements were created. So no reference to the function exists when the dom is created. The setGameAreaBounds function gets called after the dom is ready - onLoad. JavaScript functions each have their own scope so you need to pass this from the parent using an unique reference. Then you can assign the names you want to the functions.
A better approach would be to define all scripts after
Many programs use an onReady function that waits until the dom is loaded before defining any javascript functions. This is a good approach.
I'm learning javascript and I'm having trouble figuring out why my script is not working. I'm guessing its because the imageIn and imageOut functions don't have access to the counter variable. How would I go about fixing this? Both imageIn and imageOut have errors in my error console 'undefined'.
<style type="text/css">
ul {
list-style-type:none;
}
</style>
<body>
<div id="slideShow">
<ul>
<li>
<img src="stockboat.png" alt="Steam Boat" id="boat" />
</li>
</ul>
</div>
<script type="text/javascript" src="getElementsByClassName.js"></script>
<script type="text/javascript">
var image = document.getElementsByTagName('img');
for (i = 0, ii = image.length; i < ii; i++) {
image[i].style.opacity = "0.5";
image[i].addEventListener('mouseover', imageIn, 'false');
image[i].addEventListener('mouseout', imageOut, 'false');
}
function imageIn() {
image[i].style.opacity = "1";
}
function imageOut() {
image[i].style.opacity = "0.5";
}
</script>
</body>
</html>
I think you're right about it not recognizing your iteration variable, you'll have to do:
Use reference object:
function imageIn() {
this.style.opacity = "1"; // use "this" instead of image array
}
function imageOut() {
this.style.opacity = "0.5"; // use "this" instead of image array
}
-or-
Closure Approach:
image[i].addEventListener('mouseover'
, (function(obj){return function(){imageIn(obj)};})(image[i])
, 'false');
image[i].addEventListener('mouseout'
, (function(obj){return function(){imageOut(obj)};})(image[i])
, 'false');
Need to change function definition:
function imageIn(obj) { // added parameters "obj"
obj.style.opacity = "1";
}
This method allows you to reference the loop variable, which is nice to have as an example for when using setTimeOut in a loop - so you can reuse code later :)
You may try jsfiddle and put the 2 functions imagineIn and imageOut before the code that use them.
You need to wait for the dom to finish loading before accessing any elements.
Wrap your code in with the following:
window.addEventListener('load', function () {
. . . // Your code
});
Additionally, your i variable is wrapped in the closure of both imageIn and imageOut. This means that whenever any image is receives a mouseover or mouseout event, the opacity will always change for the last image in your list of images.
To fix this, you can bind a scope to the functions:
image[i].addEventListener('mouseover', imageIn.bind(image[i]), false);
Then in your imageIn function you would do:
this.style.opacity = "1";
One last point: you are passing the string 'false' as the third argument to addEventListener. In JavaScript, any non-empty string will evaluate to true, so you should pass the boolean value false instead to prevent event bubbling.
I find jQuery incredibly time-saving and intuitive. You just have to get used to throwaway functions. Check it out! http://jsfiddle.net/wgxZu/1/
<style type="text/css">
ul {
list-style-type:none;
}
</style>
<body>
<div id="slideShow">
<ul>
<li>
<img src="http://placekitten.com/100/100" alt="Steam Boat" id="boat" />
</li>
<li>
<img src="http://placekitten.com/200/100" alt="Steam Boat" id="boat" />
</li>
<li>
<img src="http://placekitten.com/300/60" alt="Steam Boat" id="boat" />
</li>
</ul>
</div>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
var image = document.getElementsByTagName('img');
for (i = 0, ii = image.length; i < ii; i++) {
image[i].style.opacity = "0.5";
$(image[i]).hover(function(){$(this).css({"opacity":"1.0"})},
function(){$(this).css({"opacity":"0.5"})});
}
</script>
</body>
</html>
There could be errors in your <script type="text/javascript" src="getElementsByClassName.js"></script> which is causing the rest of your script to stop executing.
In addition to the answers mentioned here I would offer some other advice:
Define your counter variables: var i = 0, ii = image.length. Otherwise you might end up using some global i and ii variables that are already set....
Use an inspector like Chrome Developer Tools to find issues in your JS code.
Add and remove CSS classes rather than changing the elements styles. This will allow you to make multiple style changes with little effort.
Learn to make use of Event Delegation in your code, it will help you in the long run especially when you want to start making use of dynamic content.
Good luck with your learning.
Also, as far as getting the code to work you can take a look at this jsFiddle which uses your code with a few modifications: http://jsfiddle.net/b9Fua/