I'm working on a bootcamp and some guys and I have created a group. We are trying to dynamically create html elements using pure JavaScript. The elements are there but we get an error running and we want to be able to go back and use/grab those elements later. Any advice on what we are doing wrong would be much appreciated.
The HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript Grid</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="grid"></div>
<script src="js/script.js" type="text/javascript"></script>
</body>
</html>
The js:
(function() {
var grid = document.getElementById("grid");
for (var i = 0; i < 5; i++) {
var temp = document.createElement("DIV");
temp.className = "row";
grid.appendChild(temp);
}
var row = grid.getElementsByClassName("row");
})();
The CSS:
.grid {
height: 100%;
width: 100%;
overflow: auto;
background-color: black;
}
.row {
overflow: auto;
}
.box {
padding: 0;
box-sizing: border-box;
background-color: white;
height: 100px;
float: left;
}
Thanks!
I see no error on your code.
your divs are collected and you can play with them around. take a look to the jsfiddle and open your console. (press F12 or inspect element on right mouse click).
(function() {
var grid = document.getElementById("grid");
for (var i = 0; i < 5; i++) {
var temp = document.createElement("DIV");
temp.className = "row";
grid.appendChild(temp);
}
var row = grid.getElementsByClassName("row");
row[row.length - 1].style.borderColor = "blue";
row[0].style.borderColor = "red";
})();
and the css
.row {
background.color:#f2f2f2;
border: 1px solid #dadada;
margin-bottom:10px;
height:20px;
}
http://jsfiddle.net/hu7a7k0s/
Related
I am sorry for the norwegian variable names in the js file, but if u try to click a cell, you will see that the height of it will resize, I am wondering if anyone have an easy and quick change!
<!doctype html>
<html lang="no">
<head>
<title> Standardoppsett </title>
<meta charset="utf-8">
</head>
<style>
.board {
table-layout: fixed;
width: 360px;
height: 360px;
border: 32px solid;
border-color: darkslategray;
border-radius: 5px;
}
.firkant {
border: 1px black solid;
}
.hvit{
background:white;
}
.svart{
background:grey;
}
td:hover {
background: lightgreen;
cursor: pointer
}
</style>
<body>
<div>
<table class="board"></table>
</div>
<script>
let tableEl = document.querySelector("table")
for(let i = 1; i < 9; i++) {
let trEl = document.createElement('tr');
for(let j = 1; j < 9; j++) {
let tdEl = document.createElement('td');
tdEl.setAttribute("id","rute"+i+j)
tdEl.addEventListener("click",plasserDronning)
trEl.appendChild(tdEl);
// Bare på grunn av css
tdEl.className = (i%2 === j%2) ? "hvit firkant" : "svart firkant";
}
tableEl.appendChild(trEl);
}
turTeller = 0
function plasserDronning(e){
let firkantTrykket = e.target
console.log(firkantTrykket.id)
if (turTeller == 0) {
if(firkantTrykket = e.target){
firkantTrykket.innerHTML = "a";
}
turTeller = 1
}
else if(turTeller == 1) {
if(firkantTrykket = e.target){
firkantTrykket.innerHTML = "b";
}
turTeller = 2
}
}
</script>
</body>
</html>
So far I have tried basically everything I am aware of, I have tried to set the table layout to fixed, I have tried to set the "td's" posistion to top and a lot more, if anyone knows what I can do, it would mean a lot!
In above code I suggest to add height properties in you td tag's class that will solve your issue.
if you want to more responsive and you can write media queries.or using other framework like bootstap.
.hvit{
background:white;
height:20px;
}
.svart{
background:grey;
height:20px;
}
You can add height:calc(100% / 8); to the firkant (td) class to prevent the cell from growing.
This way the cell will scale with the table if you decide to increase the table size or make it dynamic.
I cannot manage to reproduce the problem in fiddle.
The problem occurs when is exactly 1286px wide (in the inspector), but it might also happen at other widths.
Clicking the elements changes the height of the body, from 86 to 85.9833.
https://i.imgur.com/rGJPFyW.png
https://gfycat.com/acidicmarvelousabyssiniancat
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
body {font-family: monospace; background: #222; color:#aaa;}
html{scrollbar-color: grey black;}
#ui_tags{
column-width: 80px;
margin: 1em;
padding: 1em;
background-color: #181818;
/*width: 90%;*/
}
.tag_select {
cursor:pointer;
color:#aaa;
}
.tag_select:hover {
background: #222;
}
.tag_select:active {
background: #f00;
}
p {margin-bottom:1px;margin-top:1px;}
</style>
<body>
<div id="ui">
<div id="ui_tags"><p class="tag_select">4ch:114</p><p class="tag_select">avtr:54</p><p class="tag_select">awe:53</p><p class="tag_select">btfl:211</p><p class="tag_select">cat:319</p><p class="tag_select">charc:19</p><p class="tag_select">cmc:145</p><p class="tag_select">dung:15</p><p class="tag_select">frnc:53</p><p class="tag_select">fun:5</p><p class="tag_select">inspr:192</p><p class="tag_select">lego:16</p><p class="tag_select">lndsc:63</p><p class="tag_select">mchn:5</p><p class="tag_select">meh:42</p><p class="tag_select">mnstr:87</p><p class="tag_select">pgrmh:62</p><p class="tag_select">pltc:239</p><p class="tag_select">ppl:22</p><p class="tag_select">pxlr:72</p><p class="tag_select">shrlt:79</p><p class="tag_select">txl:145</p><p class="tag_select">urbn:6</p><p class="tag_select">vlgr:135</p><p class="tag_select">wrd:23</p>
</div>
</div>
<div id="gallery">
</div>
<script type="text/javascript">
window.onload = function(){
var tag_selects = document.getElementsByClassName("tag_select");
for(var i = 0, size = tag_selects.length; i < size ; i++){
// var elem = tag_selects[i].children[1];
var elem = tag_selects[i];
elem.addEventListener("click", function(event){
char = this.innerHTML;
document.getElementById('gallery').innerHTML = char;
});
}
}
</script>
</body>
</html>
I don't know if I'm using bad practices, or how to avoid this problem. I think column-width is not really stable and should be avoided but I'm not sure.
I modified the <p> to <span> and the problem went away.
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
Please, take a look at this fiddle (I am using Vue.js to generate lots of DOM nodes here, but my question doesn't seem to be a Vue related issue): https://jsfiddle.net/dmaevsky/kswj23r1/117/ .
When I am monitoring performance using Chrome's performance tool while pressing the button in a rapid succession, I am seeing 42ms 'Update Layer Tree' rendering delay, which makes sense, since the stuff is moving on page, so why not (I am still wondering btw whether there's a way to eliminate this).
However, things get awry when I uncomment the line 30, thus manually setting the td's styles in Javascript:
//nr = 50, nc = 50;
for (let i = 0; i < nr; i++) {
for (let j = 0; j < nc; j++) {
this.$refs[i + ':' + j][0].style.color = 'blue';
}
}
When I now monitor the performance I see all 2500 TD nodes added to the "Recalculating styles" in Chrome when 'Shift down' button is pressed. I just cannot see why that would make any sense ? Using a class instead of setting styles manually does not cause this to happen.
This is just an attempt to understand the browser's style invalidation logic, not a real application, so the number of DOM nodes here is intentionally kept higher than one would reasonably need in a real world application, though close enough.
UPDATE:
This actually DOES seem to be a Vue.js issue finally. I have re-written the code in pure JS (complete HTML below), and I do not observe the same effect anymore.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Create table test</title>
<style>
body {
font-family: Helvetica;
}
#app {
background: #fff;
padding: 20px;
}
#app {
position: relative;
}
#pane {
position: absolute;
}
.table {
table-layout: fixed;
border-collapse: collapse;
margin: 0;
padding: 0;
border: hidden;
width: 8000px;
height: 1600px;
}
.cell {
width: 100px;
height: 20px;
line-height: 16px;
box-sizing: border-box;
padding: 2px;
background: white;
overflow: hidden;
}
</style>
</head>
<body>
<noscript>
<strong>Need JS</strong>
</noscript>
<button onclick="shift()">Shift down</button>
<div id="app">
<div id="pane"></div>
</div>
</body>
</html>
<script>
var pos = 0;
function shift() {
pos++;
document.getElementById('pane').style.top = pos + 'px';
}
function createTable(nr, nc) {
let table = document.createElement('table');
table.className = 'table';
for (let i = 0; i < nr; i++) {
let tr = document.createElement('tr');
for (let j = 0; j < nc; j++) {
let td = document.createElement('td');
let span = document.createElement('span');
span.innerHTML = i + j;
td.className = 'cell';
td.style.color = 'blue';
td.appendChild(span);
tr.appendChild(td);
}
table.appendChild(tr);
}
return table;
}
document.getElementById('pane').appendChild(createTable(80, 80));
</script>
Question to Vue.js experts then: what does Vue do to DOM to warrant the observed behavior in the first fiddle???
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/