Generate random number of divs - javascript

I can't make the script to create random amount of divs. In this specific example between 5 and 20. The problem is in the for loop maybe? The function that generates random numbers is working correctly below in the random color function, I guess it is not recognized for some reasons. Also I am not getting any errors in firebug.
Example:
function generateDiv(){
var dfrag = document.createDocumentFragment();
var count = generateRandom(5, 20);
var i=0;
for (var i = 0; i < count; i++){
var div = document.createElement("div");
dfrag.appendChild(div);
}
}
var divs = document.getElementsByTagName("div");
for (i = 0; i < divs.length; i++) {
div = divs[i];
alterDivStyle(div);
}
function rndColor() {
var r = ('0' + generateRandom(0,255).toString(16)).substr(-2), // red
g = ('0' + generateRandom(0,255).toString(16)).substr(-2), // green
b = ('0' + generateRandom(0,255).toString(16)).substr(-2); // blue
return '#' + r + g + b;
}
function generateRandom(min, max) {
var number = Math.floor(Math.random() * (max - min )) + min;
return number;
}
function alterDivStyle(div){
div.style.width = generateRandom(20, 100) +"px";
div.style.height = generateRandom(20, 100) +"px";
div.style.backgroundColor = rndColor();
div.style.color = rndColor();
div.style.position = "absolute";
div.style.border = "solid";
div.style.borderColor = rndColor();
div.style.borderWidth = rndColor();
div.style.borderRadius = generateRandom(0, 10)+"px";
div.innerHTML = "<strong>div</strong>";
};

You never added the document fragment to the DOM
"DocumentFragments are DOM Nodes. They are never part of the main DOM tree. The usual use case is to create the document fragment, append elements to the document fragment and then append the document fragment to the DOM tree. In the DOM tree, the document fragment is replaced by all its children."
https://developer.mozilla.org/en-US/docs/Web/API/document.createDocumentFragment

1) You closed the "generateDiv function" in the wrong place, move the closing bracket from before the "var divs" to after the "var divs" loop.
2) You are altering all the existing divs in the DOM:
var divs = document.getElementsByTagName("div");
Don't do that, use dfrag.
3) Like Matthew said, you have to add dfrag to the DOM.

function generateDiv(){
var dfrag = document.createDocumentFragment();
var count = generateRandom(5, 20);
var i=0;
for (var i = 0; i < count; i++){
var div = document.createElement("div");
dfrag.appendChild(div);
}
for (i = 0; i < dfrag.childNodes.length; i++) {
div = dfrag.childNodes[i];
alterDivStyle(div);
}
document.body.appendChild(dfrag);
}
function rndColor() {
var r = ('0' + generateRandom(0,255).toString(16)).substr(-2), // red
g = ('0' + generateRandom(0,255).toString(16)).substr(-2), // green
b = ('0' + generateRandom(0,255).toString(16)).substr(-2); // blue
return '#' + r + g + b;
}
function generateRandom(min, max) {
var number = Math.floor(Math.random() * (max - min )) + min;
return number;
}
function alterDivStyle(div){
div.style.width = generateRandom(20, 100) +"px";
div.style.height = generateRandom(20, 100) +"px";
div.style.backgroundColor = rndColor();
div.style.color = rndColor();
div.style.position = "absolute";
div.style.border = "solid";
div.style.borderColor = rndColor();
div.style.borderWidth = rndColor();
div.style.borderRadius = generateRandom(0, 10)+"px";
div.innerHTML = "<strong>div</strong>";
};
generateDiv();

Related

Unable to target JS generated button within an array with a function, getting "Cannot read property 'setAttribute' of null" error

I'm simply trying to cause a specific button background to change when I click it.
I generated 100 buttons (in the hopes of making a simple game, later on) as an array through a for loop, while assigning an id and a distinct function call (based on the incrementing 'i' value of the loop), and am unable to actually cause the background to change upon clicking, getting the followed error instead
"Uncaught TypeError: Cannot read property 'setAttribute' of null
at showOptions (brain.js:31)
at HTMLButtonElement.onclick (index.html:15)"
My code goes as follows
var btn = [];
function generateBoard() {
for (i = 0; i < 100; i++) {
var modulo = i % 10;
var up, forLeft;
btn[i] = document.createElement("BUTTON");
var element = document.getElementById("body");
//btn[i].innerText = "CLICK ME";
element.appendChild(btn[i]);
btn[i].style.backgroundColor = "white";
btn[i].id = i;
btn[i].style.width = "50px";
btn[i].style.height = "40px";
btn[i].style.position = "absolute";
btn[i].style.top = modulo * 100;
btn[i].style.left = Math.floor(i / 10) * 100;
btn[i].x = (i + 10) % 10;
btn[i].y = Math.floor(i / 10);
document
.getElementById(btn[i].id)
.setAttribute("onclick", "showOptions(i)");
btn[i].innerText = btn[i].id;
console.log(
btn[i].id +
" " +
btn[i].style.left +
" " +
btn[i].style.top +
" " +
btn[i].x +
" " +
btn[i].y
);
}
}
generateBoard();
function showOptions(i) {
document.getElementById(i).setAttribute("style", "background-color: red;"); //this is line 31
}
in console.log I actually get the correct digit as btn[i].id, oddly enough.
the (index.html:15) line of the error is simply
</html>
There are multiple issues with your code.
You should get body element with getElementsByTagName, which returns array. So pick first element.
Setting onclick attribute should use value of i not text i.
var btn = [];
function generateBoard() {
for (i = 0; i < 100; i++) {
var modulo = i % 10;
var up, forLeft;
btn[i] = document.createElement("BUTTON");
var element = document.getElementsByTagName("body")[0];
//btn[i].innerText = "CLICK ME";
element.appendChild(btn[i]);
btn[i].style.backgroundColor = "white";
btn[i].id = i;
btn[i].style.width = "50px";
btn[i].style.height = "40px";
btn[i].style.position = "absolute";
btn[i].style.top = modulo * 100;
btn[i].style.left = Math.floor(i / 10) * 100;
btn[i].x = (i + 10) % 10;
btn[i].y = Math.floor(i / 10);
document.getElementById(btn[i].id).setAttribute('onclick', 'showOptions(' + i + ')');
btn[i].innerText = btn[i].id;
console.log(btn[i].id + " " + btn[i].style.left + " " + btn[i].style.top + " " + btn[i].x + " " + btn[i].y);
}
}
generateBoard();
function showOptions(i) {
document.getElementById(i).setAttribute("style", "background-color: red;"); //this is line 31
}
I've reworked your code, fixing a few issues. I assume you have an element with id body, which is distinct from the body element, which can be accessed through document.body.
var buttons = [];
function generateBoard(){
for(i = 0; i < 100; i++) {
var modulo = i % 10;
buttons[i] = document.createElement("BUTTON");
document.getElementById("body").appendChild(buttons[i]);
//buttons[i].innerText = "CLICK ME";
buttons[i].style.backgroundColor = "white";
buttons[i].id = i;
buttons[i].style.width = "50px";
buttons[i].style.height = "40px";
buttons[i].style.position = "absolute";
buttons[i].style.top = modulo * 100;
buttons[i].style.left = Math.floor(i / 10) * 100;
buttons[i].x = (i + 10) % 10;
buttons[i].y = Math.floor(i / 10);
buttons[i].addEventListener('click', function(event) {
// This code is run when the button is clicked
// Note I am passing the element, rather than an id
showOptions(this);
});
buttons[i].innerText = i;
console.log(buttons[i].id + " " + buttons[i].style.left + " " + buttons[i].style.top + " " + buttons[i].x + " " + buttons[i].y);
}
}
generateBoard();
function showOptions(button){
button.style.backgroundColor = "red";
}
Rather than assigning and attempting to use an ID attribute you can target the clicked element by referring to a property of the event itself. If you were to analyse the event ( use console ) you would notice several properties - the target allows access to the element itself which helps simplify the showOptions function. In this instance you could also simply use this to refer to the button itself from within showOptions - which would make it even simpler - such as this.style.backgroundColor='red';
let bttns=[];
const generateBoard=function( s=100 ){
const showOptions=function(e){
e.target.style.backgroundColor='red';
};
for( let i=0; i < s; i++ ){
/* create a new button and add properties */
let bttn=document.createElement('button');
bttn.setAttribute('id',i);
bttn.setAttribute('data-x',((i+10)%10));
bttn.setAttribute('data-y',Math.floor(i/10));
bttn.style.left=( Math.floor( i / 10 ) * 100 )+'px';
bttn.style.top=( ( i % 10 ) * 100 )+'px';
bttn.style.width = '50px';
bttn.style.height = '40px';
bttn.style.position = 'absolute';
bttn.innerText=i;
/* bind event listener */
bttn.addEventListener('click', showOptions );
/* add to the DOM */
document.body.appendChild( bttn );
/* if it is important to have in an array... */
bttns.push( bttn );
}
}
document.addEventListener('DOMContentLoaded',(e)=>{
generateBoard( 100 );
})
Adding arbitrary attributes to elements is not best practise - rather than assigning x and y you should make use of dataset attributes instead - so data-x and data-y would be correct.

JavaScript: How Can I Make A Var "Array" Work?

Is there a way to name a var using a sort of "Array?" My code is this:
for(var i = 0; i < (getHorizontalSquares * getVerticalSquares); i++){
var Square[i] = document.createElement("div");
Square[i].style.position = "relative";
Square[i].style.float = "left";
Square[i].style.width = "50px";
Square[i].style.height = "50px";
Square[i].id = "square" + (i + 1);
for(var ii = 0; ii < 6; ii++){
var TestColor = TestColorArray[Math.round(Math.random()*(TestColorArray.length - 1))];
getTestColor += TestColor;
}
Square[i].style.backgroundColor = "#" + getTestColor;
SquareCont.appendChild(Square[i]);
}
I know my code doesn't work, but I want to implement the same idea so I can get a result of this:
var Square1...
var Square2...
var Square3...
var Square4...
var Square5...
etc
I also tried doing a "Concentration" var, but it didn't work. How do I do this so the document doesn't append the same square multiple times?
var Square = {};
var SquareCont = document.createElement('div');
var getHorizontalSquares = 10;
var getVerticalSquares = 10;
var TestColorArray = ['a','b','c','f','e','0','1','2','3','3','4','5'];
var getTestColor = '';
for(var i = 0; i < (getHorizontalSquares * getVerticalSquares); i++){
Square['Square'+i] = document.createElement("div");
Square['Square'+i].style.position = "relative";
Square['Square'+i].style.float = "left";
Square['Square'+i].style.width = "50px";
Square['Square'+i].style.height = "50px";
Square['Square'+i].id = "square" + (i + 1);
for(var ii = 0; ii < 6; ii++){
var TestColor = TestColorArray[Math.round(Math.random()*(TestColorArray.length - 1))];
getTestColor += TestColor;
}
Square['Square'+i].style.backgroundColor = "#" + getTestColor;
SquareCont.appendChild(Square['Square'+i]);
getTestColor = '';
}
console.log(Square);
This example does what you want using an object instead of an array, but meets your desire to dynamically create accessible Square1, Square2, etc... They are all contained in Square. In the console with this snippet, you will see that 100 squares are created and added to the Square object. They will be accessible by Square.SquareX (where X is some number), or Square['SquareX'], or Square['Square'+X] where X is some number again.
Your declaration syntax is not valid. But, I think the larger point you are trying to get to is to be able to populate an array with dynamically created elements and that you can do:
var squares = []; // Array must exist before you can populate it
var testColorArray = ["green", "yellow", "blue", "orange", "silver"];
var getTestColor = null;
function makeSquares(count){
for(var i = 0; i < count; i++){
// Just create the element and configure it. No need to worry about the array yet
var element = document.createElement("div");
element.style.float = "left";
element.style.width = "75px";
element.style.height = "75px";
element.id = "square" + (i + 1);
element.style.backgroundColor = testColorArray[Math.floor(Math.random()* testColorArray.length)];
element.textContent = element.id;
squareCont.appendChild(element);
// Now, add the element to the arrray
squares.push(element);
}
// Test:
console.log(squares);
}
makeSquares(10);
<div id="squareCont"></div>

Repeat Horizontally the same image on div

Im making a game with javascript, css and html only, it's a simple game, where the character must hit the cakes so you get more points. Im having an issue, on the cakes movement and positioning. I could set them on the screen randomly and going horizontally to the right, but I can't that my function repeats itself nor limit the cakes to a certain zone of the screen.
This is my HTML:
<script language ="javascript">
function createNewCake() {
var myDiv = document.createElement('div');
myDiv.id = "cake0";
myDiv.className = "cake-div";
return myDiv;
}
function rotateElement(elem, degrees) {
var rad=degrees*(Math.PI / 180.0);
var text = "rotate(" + degrees + "rad)";
elem.style.transform = text;
elem.style.webkitTransform = text;
elem.style.mozTransform = text;
elem.style.oTransform = text;
elem.style.msTransform = text;
}
var cakes = new Array();
var colors = new Array();
colors[0] = "images/bolo1.png";
colors[1] = "images/bolo2.png";
colors[2] = "images/bolo3.png";
colors[3] = "images/maca.png";
for (var i=0; i<20; i++) {
var aCake = createNewCake();
aCake.id = "cake" + i;
var index = Math.floor(Math.random() * (colors.length + 1));
aCake.style.backgroundImage = "url('" + colors[index]+ "')";
aCake.style.left = Math.floor(Math.random() * window.innerWidth);
aCake.style.top = Math.floor(Math.random() * window.innerHeight);
document.body.appendChild(aCake);
cakes.push(aCake);
}
animate();
function animate() {
requestAnimationFrame(animate);
for (var i=0; i < cakes.length; i++) {
var pixel = Number(cakes[i].style.left.replace("px",""));
cakes[i].style.left = pixel + 2 + "px";
}
}
</script>
</body>
I got it done, thanks all!
It was just if checking if the image pixel is hitting the max width! :D

JavaScript - create number of divs in loop

I'm a begginer with javaScript. and I want to create number of windows (div) with loop operation only with javaScript.
This is my code:
var numOfWindows = 3;
var arrayDiv = new Array();
for (var i = 0; i < numOfWindows; i++)
{
arrayDiv[i] = document.createElement('div');
arrayDiv[i].id = 'block' + i;
arrayDiv[i].style.backgroundColor = 'green';
arrayDiv[i].className = 'block' + i;
document.body.appendChild(arrayDiv[i]);
}
but I see a blank screen.
Your JavaScript works perfectly, if you give the created elements some content, or specific dimensions in CSS:
var numOfWindows = 3;
var arrayDiv = new Array();
for (var i = 0; i < numOfWindows; i++)
{
arrayDiv[i] = document.createElement('div');
arrayDiv[i].id = 'block' + i;
arrayDiv[i].style.backgroundColor = 'green';
arrayDiv[i].className = 'block' + i;
// setting the textContent to the 'i' variable:
arrayDiv[i].textContent = i;
document.body.appendChild(arrayDiv[i]);
}
JS Fiddle demo.
Or:
var numOfWindows = 3;
var arrayDiv = new Array();
for (var i = 0; i < numOfWindows; i++) {
arrayDiv[i] = document.createElement('div');
arrayDiv[i].id = 'block' + i;
arrayDiv[i].style.backgroundColor = 'green';
arrayDiv[i].className = 'block' + i;
// setting the class-name of the created elements:
arrayDiv[i].className = 'bordered';
document.body.appendChild(arrayDiv[i]);
}
JS Fiddle demo.
Give your div a specified width and height.
div.style.width = '10px';
div.style.heigt = '10px';
Or give it content.

Make eventlisteners unique?

So I have a problem where the eventlisteners I setup all happen to work with the same variable.
This is how it looks like:
// Prepare tooltips
for (var i = 0; i < document.getElementsByClassName("tooltip").length; i++) {
var tooltip = document.getElementsByClassName("tooltip")[i];
var input = document.getElementsByName(tooltip.id.substr(8))[0];
var offsetTop = 0;
var tmp = input;
while (tmp != null) {
offsetTop += tmp.offsetTop;
tmp = tmp.offsetParent;
}
offsetTop -= 130;
var offsetLeft = (input.offsetParent.offsetLeft + input.scrollWidth) + 50;
tooltip.innerHTML += "<div class='corner'></div>";
tooltip.style.top = offsetTop + "px";
tooltip.style.left = offsetLeft + "px";
input.addEventListener("focus", function() { document.getElementById(tooltip.id).style.display = "block"; });
input.addEventListener("blur", function() { document.getElementById(tooltip.id).style.display = "none"; });
}
In the last two lines I set the eventlisteners.
So whenever I focus an input field, no matter which one tooltip.id is always the same.
I checked the input.id before its different in every loop.
Javascript is a funny language :)
In each loop you're declaring a function which uses a reference to the variable tooltip.
Since you use the variable many times: its value changes but the reference remains the same.
When the function executes, it uses the reference (which has the last value).
Here is the solution:
(I recommend calling the method 'document.getElementsByClassName("tooltip")' only once since it causes DOM traverse.
==== CODE STARTS HERE
var toolips = document.getElementsByClassName("tooltip");
for (var i = 0; i < toolips.length; i++)
{
var tooltip = toolips[i];
var input = document.getElementsByName(tooltip.id.substr(8))[0];
var offsetTop = 0;
var tmp = input;
while (tmp != null)
{
offsetTop += tmp.offsetTop;
tmp = tmp.offsetParent;
}
offsetTop -= 130;
var offsetLeft = (input.offsetParent.offsetLeft + input.scrollWidth) + 50;
tooltip.innerHTML += "<div class='corner'></div>";
tooltip.style.top = offsetTop + "px";
tooltip.style.left = offsetLeft + "px";
// assign tooltip id to the input
input.tooltipId = tooltip.id;
// add event listeners
input.addEventListener("focus", function() { document.getElementById(this.tooltipId ).style.display = "block"; });
input.addEventListener("blur", function() { document.getElementById(this.tooltipId).style.display = "none"; });
}
==== CODE ENDS HERE

Categories

Resources