My $(".grid").mouseenter doesn't run after I press my new button, which deletes old divs (.grid) and creates new ones. So, what can I change to make it work after that. Also, why are there empty spaces above all .grid divs?
$(document).ready(function(){
createGrid();
$(".grid").mouseenter(function(){
$(this).addClass("hovered")
});
$("#new").click(function(){
clear();
createGrid(prompt("How big would you like your new grid to be (x<64)?"));
});
$("#clear").click(function(){
clear();
});
});
function clear(){
$(".grid").removeClass("hovered");
};
function gridSize(measuring, howBig){
if (howBig==null){
howBig = 16;
}
switch(measuring){
case "height":
return parseInt($("#surface").height()/howBig);
case "width":
return parseInt($("#surface").width()/howBig);
}
};
function createGrid(howBig){
$("#surface").empty();
if(howBig == null || howBig == ""){
for(var i=0; i < 16; i++){
$("#surface").prepend("<div class = 'grid' style = 'width: " +gridSize('width')+"px ; height:"+gridSize('height')+ "px;'></div>");
for(var j=0; j < 15; j++){
$("#surface").prepend("<div class = 'grid' style = 'width: " +gridSize('width')+"px ; height:"+gridSize('height')+ "px;'></div>");
}
}
}
else {
for(var i=0; i < howBig; i++){
$("#surface").prepend("<div class = 'grid' style = 'width: " +gridSize('width', howBig)+"px ; height:"+gridSize('height', howBig)+ "px;'></div>");
for(var j=0; j < howBig-1; j++){
$("#surface").prepend("<div class = 'grid' style = 'width: " +gridSize('width', howBig)+"px ; height:"+gridSize('height', howBig)+ "px;'></div>");
}
}
}
};
* { margin:0; padding:0; }
.wrapper {
width: 800px;
margin: 0px auto;
}
#reset {
width: 60px;
margin : 15px auto;
}
#surface {
margin: 0px auto;
width: 800px;
height: 800px;
}
.grid {
background-color: #D3D3D3;
margin: 0px;
display: inline-block;
}
.hovered {
background-color: black;
}
<!DOCTYPE html>
<html>
<head>
<link rel = "stylesheet" href = "css/styles.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src = "js/script.js"></script>
</head>
<body>
<div class = "wrapper">
<button id ="new">New</button>
<button id ="clear">Clear</button>
<div id = "surface"></div>
</div>
</body>
</html>
Replace:
$(".grid").mouseenter(function(){
$(this).addClass("hovered")
});
with
$("#surface").on('mouseenter','.grid',function(){
$(this).addClass("hovered")
});
This is required because your original code was attaching event handlers to the .grid elements, which you delete and create new elements (which don't have the handlers attached). You could just re-run your original code to attach new handlers when you create new elements, but using event delegation is a much better approach as you only attaching an event handler on one element (#surface) rather than on each individual .grid element, and of course, since you aren't removing and recreating the #surface element, you don't need to detach/re-attach it when you create a new grid.
You can read more about jQuery's on method and event delegation here: http://api.jquery.com/on/
As for the spacing issue, it is because you are using inline-block elements, and inline-elements will preserve atleast one space if present between elements. You can either remove all spaces (and line breaks) between the elements, or you can place font-size:0; on the #surface element to shrink the space size to nothing.
maxSize=16;
$(document).ready(function(){
createGrid(16);
$("#surface").on('mouseenter','div',function(){
$(this).addClass("hovered")
});
$("#new").click(function(){
createGrid(prompt("How big would you like your new grid to be (x<" + maxSize + ")?"));
});
$("#clear").click(function(){
$("#surface>div").removeClass("hovered");
});
});
function gridSize(measuring, howBig){
switch(measuring){
case "height":
return parseInt($("#surface").height()/howBig);
case "width":
return parseInt($("#surface").width()/howBig);
}
};
function createGrid(howBig){
howBig=parseInt(howBig);
if(howBig == NaN || howBig<1 || howBig>maxSize){
howBig=16;
}
$("#surface").empty();
for(var i=0; i < howBig*howBig; i++){
$("#surface").append("<div style='width:" +gridSize('width', howBig)+"px; height:"+gridSize('height', howBig)+ "px;'></div>");
}
};
* { margin:0; padding:0; }
.wrapper {
width: 800px;
margin: 0 auto;
}
#reset {
width: 60px;
margin : 15px auto;
}
#surface {
margin: 0 auto;
width: 800px;
height: 800px;
font-size: 0;
}
#surface>div {
background-color: #D3D3D3;
margin: 0;
display: inline-block;
}
#surface>div.hovered {
background-color: black;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/styles.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="js/script.js"></script>
</head>
<body>
<div class="wrapper">
<button id="new">New</button>
<button id="clear">Clear</button>
<div id="surface"></div>
</div>
</body>
</html>
I've also taken the liberty to clean up some of the javascript for you.
You will need to use event delegation to work with dynamically created elements
$("#surface").on('mouseenter','.grid',function(){
$(this).addClass("hovered");
});
---> https://learn.jquery.com/events/event-delegation/
it does not work because the divs created after you attach the action to it so you must to use one of this statements :
Example 1:
$("body").on('mouseenter','.grid',function(){
$(this).addClass("hovered");
})
http://api.jquery.com/on/
Example 2:
$("body").live('mouseenter','.grid',function(){
$(this).addClass("hovered");
})
http://api.jquery.com/live/
Example 3:
$("body").delegate('mouseenter','.grid',function(){
$(this).addClass("hovered");
})
http://api.jquery.com/delegate/
Related
I have a very basic little "game" here. In the for loop that says i < miniSquares.length (the last for loop in my JS code), there is an addEventListener that targets every object (the objects as divs in this case) with a class of .miniSquare. In the function executed by the addEventListener I stated at the end that I want to remove the .miniSquare class by typing this.classList.remove("miniSquare") so that the EventListener does not execute again. My logic is that if I remove the class that targets the EventListener there should be no way that the eve
const grid = document.querySelector(".grid");
let squares = [];
function createBoard() {
for (let i = 0; i < 100; i++) {
const square = document.createElement('div');
square.setAttribute("id", i);
square.setAttribute("class", "miniSquare");
grid.appendChild(square);
squares.push(square);
}
const miniSquares = document.querySelectorAll(".miniSquare");
for (let i = 0; i < miniSquares.length; i++) {
miniSquares[i].addEventListener("click", function() {
const minedArray = ["bitCoin", "rock", "rock", "rock", "rock"];
const minedRandomizer = minedArray[Math.floor(minedArray.length * Math.random())];
this.setAttribute("class", minedRandomizer);
this.classList.remove("miniSquare");
});
}
}
createBoard();
.grid{
height: 500px;
width: 500px;
display: flex;
flex-wrap: wrap;
background-color: green;
background-size: cover;
}
.miniSquare {
height: 40px;
width: 40px;
margin: 3px;
background-color: brown;
background-size: cover;
}
.rock{
height: 40px;
width: 40px;
margin: 3px;
background-color: grey;
background-size: cover;
}
.bitCoin{
height: 40px;
width: 40px;
margin: 3px;
background-color: yellow;
background-size: cover;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Bitcoin Mining</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="grid">
</div>
<script src="app.js" charset="utf-8"></script>
</body>
</html>
nt listener would work on it again (basically I don't want the object to be clicked more than once, once it is clicked nothing shall happen if clicked again). Here is the code:
You can extract the event handler in a named function and make it deregister itself using removeEventListerner:
function onClick() {
const minedArray = ["bitCoin", "rock", "rock", "rock", "rock"];
const minedRandomizer = minedArray[Math.floor(minedArray.length * Math.random())];
this.setAttribute("class", minedRandomizer);
this.classList.remove("miniSquare");
this.removeEventListener("click", onClick)
}
for (let i = 0; i < miniSquares.length; i++) {
miniSquares[i].addEventListener("click", onClick);
}
if you have attached an event handler to an elemenet, it needs to be removed specifically from the element. It does not matter what was the CSS selector you would have used to serach the element, and now the css selector is not applicable to the element.
I have written this code to get the squares of a grid to change their background color to black upon a mouseover event. It works when the page initially loads, but if I create a new grid the mouseover event no longer works.
I updated the original post with a snippet. Sorry I didn't do that from the beginning.
let number = 16;
makeGrid(number);
function makeGrid(number) {
for (let i=0; i < number; i++) {
for (let j=0; j < number; j++) {
const rows = document.createElement('div');
const container = document.getElementById('container')
rows.setAttribute('class', 'rows');
container.appendChild(rows);
}
}
container.style.gridTemplateColumns = `repeat(${number}, 1fr)`;
container.style.gridTemplateRows = `repeat(${number}, 1fr)`;
}
//create new grid with on button
let newGrid = document.getElementById('newGrid');
newGrid.addEventListener('click', () => {
let number = prompt('Enter a number');
let container = document.getElementById('container');
container.textContent = '';
makeGrid(number);
})
//change background color to black
let changeClass = document.querySelectorAll('.rows');
changeClass.forEach((item) => {
item.addEventListener('mouseover', e => {
item.style.backgroundColor = 'black';
})
})
body {
background-color: rgb(5, 51, 5) ;
}
#container {
margin: auto;
width: 500px;
height: 500px;
display: grid;
border-style: solid;
border-width: thin;
border-color: lightslategray;
background-color: white;
}
.rows{
}
.black { background-color: black;
}
#header {
text-align: center;
}
#button {
text-align: center;
}
#footer {
text-align: center;
}
#newGrid {
background-color: lightgray;
color: darkcyan;
font-size: 20px;
padding: 12px 28px;
border-radius: 0px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Etch-a-Sketch</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1 id='header'>Etch-a-Sketch</h1>
<br>
<div id='button'>
<button id='newGrid' class='button'>New Grid</button>
</div>
<br>
<br>
<div id='container'></div>
<br>
<footer id='footer'>Made by: Joe Maniaci</footer>
<script src="main.js"></script>
</body>
</html>
When you query the DOM with document.querySelectorAll('.rows') and add the event listeners, there is only one "grid" in the DOM at that time. When a "grid" is subsequently added to the DOM, as triggered by the user's click event, you must instantiate event listeners on the newly added DOM nodes too.
A way to avoid this problem and a better approach overall in your situation is to use delegated event listeners. For example:
document.addEventListener('mouseover', e=>{
if(e.target.matches(‘.myClickableItemClass’){
e.target.style.backgroundColor = 'black';
}
}
Learn more about event delegation here: https://medium.com/#bretdoucette/part-4-what-is-event-delegation-in-javascript-f5c8c0de2983
I am trying to create a checker board using pure JavaScript, not jQuery.
I have created the first row, but cannot seem to "stack" the rows to create a full board. If there is a better way to go about this than the road I'm going down, please enlighten me.
<!DOCTYPE html>
<html>
<head>
<title>Checkerboard</title>
<style>
.box {
height: 50px;
width: 50px;
border: 1px solid black;
display: inline-block;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
<script type="text/javascript">
var row = function (node, count) {
for (var i = 1; i < count; i++) {
if (i % 2 === 0) {
copy = node.cloneNode(true);
node.parentNode.insertBefore(copy, node).style.backgroundColor = "white";
} else {
copy = node.cloneNode(true);
node.parentNode.insertBefore(copy, node).style.backgroundColor = "red";
}
}
}
row(document.querySelector('.box'), 8);
</script>
</html>
Your code works fine, you just need to actually run the function you've created:
row(document.getElementsByClassName("box")[0], 50);
JSFiddle: http://jsfiddle.net/63dcjsk4/
Edit
If you're talking about the gap that appears between rows, fix this by using float and removing the inline-block display:
.box {
border: 1px solid black;
height: 50px;
float: left;
width: 50px;
}
JSFiddle: http://jsfiddle.net/63dcjsk4/1/
Background:
I started Javascript the other day and built this sketch pad:
http://frankpeelen.github.io/sketch-pad/
following alongside the instructions on:
http://www.theodinproject.com/web-development-101/javascript-and-jquery
Problem:
It's basically finished, and works fine except for when creating a new grid with the "New" button. All of a sudden the 'squares' stop responding to 'hover' events. I've searched, but have been unable to find any similar problems. Any ideas?
Code:
$(document).ready(function() {
var build = function(h, w) {
var height = h;
var width = w;
//Loop through height to create rows
for (i = 1; i <= height; i++) {
$("#sketchpadcontainer").append("<div class='row'></div>");
//Loop through width to create divs in each row
for (j = 1; j <= width; j++) {
$(".row:last-child").append("<div class='sqrcontainer'><div class='square'></div></div>");
}
}
};
//Build default 16x16 grid
build(16, 16);
$("button").click(function() {
var size = parseInt(prompt("How many squares per side would you like? Please enter a number."));
//In case the number entered > 50
if (size > 50) {
$(".row").remove();
build(50, 50);
alert("The number you entered was too large. The number 50 has been used instead.")
}
//In case a non-number is entered
else if (isNaN(size)) {
$(".row").remove();
build(16, 16);
alert("You didn't enter a number. The default of 16 has been used.")
}
//In case a number <= 50 is entered
else {
$(".row").remove();
build(size, size);
}
})
$(".square").hover(
//Mouse in
function () {
$(this).css("background-color", "blue");
},
//Mouse out
function () {} );
});
html, body, #sitecontainer {
height: 100%;
width: 100%;
margin: 0px;
}
#sketchpadcontainer {
}
button {
display: block;
margin: 0 auto;
margin-top: 2em;
margin-bottom: 1em;
}
#sketchpadcontainer {
}
.row {
text-align: center;
}
.sqrcontainer {
height: 1.5em;
width: 1.5em;
display: inline-block;
}
.square {
width: 1em;
height: 1em;
margin: .1em;
border-color: black;
border-style: solid;
border-radius: .1em;
}
<!DOCTYPE html>
<head>
<title>Sketch Pad</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type='text/javascript' src="js/javascript.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="sitecontainer">
<div id="buttoncontainer">
<button type="button">New</button>
</div>
<div id="sketchpadcontainer">
</div>
</div>
</body>
You are deleting the divs before the build method. That means the hover listeners will be deleted to. You have to add them to the .sqare elements again.
Just move
$(".square").hover(
//Mouse in
function () {
$(this).css("background-color", "blue");
},
//Mouse out
function () {} );
inside your build method
change $(".square").hover(
to $(document).on("hover" ,".square", function(){ . . . })
Ur problem in $(".square").hover( - work after $(document).ready, but after u appending new rows - document ready dont triggering, and ur elements have not events, and trigger .on work on every elems on page, even on dynamically added.
I have a group of divs which I'm dynamically generating when a button is clicked with the class, "brick". This gives them dimension and starting position of top: 0. I'm trying to get them to animate to the bottom of the view using a css transition with a second class assignment which gives them a bottom position: 0;. Can't figure out the syntax for adding a second class to elements with a pre-existing class. On inspection they only show the original class of, "brick".
HTML
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="container">
<div id="button" >Click Me</div>
</div>
</body>
</html>
CSS
#container {
width: 100%;
height: 100vh;
padding: 10vmax;
}
#button {
position: fixed;
}
.brick {
position: relative;
top: 0;
height: 10vmax;
width: 20vmax;
background: white;
margin: 0;
padding: 0;
transition: all 1s;
}
.drop {
transition: all 1s;
bottom 0;
}
The offending JS:
var brickCount = function() {
var count = prompt("How many boxes you lookin' for?");
for(var i=0; i < count; i++) {
var newBrick = document.createElement("div");
newBrick.className="brick";
document.querySelector("#container")
.appendChild(newBrick);
}
};
var getBricks = function(){
document.getElementByClass("brick");
};
var changeColor = function(){
getBricks.style.backgroundColor =
'#'+Math.floor(Math.random()*16777215).toString(16);
};
var addDrop = function() {
getBricks.brick = "getBricks.brick" + " drop";
};
var multiple = function() {
brickCount();
getBricks();
changeColor();
addDrop();
};
document.getElementById("button").onclick = function() {multiple();};
Thanks!
You can add a class to an element by doing the following:
element.className = element.className + " drop";
This is just a single string of classnames, so if you're appending, don't forget to add the space.
See https://developer.mozilla.org/en-US/docs/Web/API/Element.className
If you wanna use pure javaScript classList
HTML:
<div id="testdiv" class="brick"></div>
javaScript:
document.getElementById("testdiv").classList.add("anotherclass");
alert(document.getElementById("testdiv").className);
http://jsfiddle.net/Dinizworld/PfWqy/1/
If you wanna use jQuery addClass
HTML:
<div id="testdiv" class="brick"></div>
jQuery:
$(".brick").addClass("numbertwo");
alert($("#testdiv").prop("class"));
http://jsfiddle.net/Dinizworld/UN4gK/