Building HTML using loops in JS - javascript

Afternoon all, I am trying to build some HTML elements in JS through a loop within which I have another loop. I have written the HTML so I know what I want, so I have now tried to translate it into the JS.
The HTML I want to build (this will be a 3x3 grid):
<div class="grid">
<div class="square-row d-flex flex-row">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>
<div class="square-row d-flex flex-row">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>
<div class="square-row d-flex flex-row">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>
</div>
the JS code I have written (sorry for the poor formating (my first Stackoverflow post and I cannot get it to behave):
function generateGrid(requirement) {
let grid = `
<div class="grid">
`;
if (requirement) {
for (let i = 0; i < gridSize; i++) {
let gridRow = `
<div class="square-row d-flex flex-row">
`;
for (let s = 0; s < gridSize; s++) {
let square = `
<div class="square squares" id="${i}"></div>
`;
gridRow += square;
}
gridRow +=`
</div>
`;
}
} else {
for (let i = 0; i < gridSize; i++) {
let gridRow = `
<div class="square-row d-flex flex-row">
`;
for (let x = 0; x < gridSize; x++) {
let square =`
<div class="square squares" id="square${i}" onclick="addColour(${i})"></div>
`;
gridRow += square;
}
gridRow +=`
</div>
`;
}
}
grid += `
</div>
`;
return grid;
}
I end up with this when I run it:
<div class="grid">
</div>
I have used the keyword 'debugger' in the middle of the loop and it is moving through it. gridSize is the value of 3, so the outer loop should run three times with the inner loop also running three times for each run of the outer.
Any help or advice would be appreciated.

Im not 100% sure exactly what you meant but it seems your issue is a simple mistake of forgetting to add the gridRow to the grid.
let gridSize = 3
function generateGrid(requirement) {
let grid = `<div class="grid">\n`;
if (requirement) {
for (let i = 0; i < gridSize; i++) {
let gridRow = `\t<div class="square-row d-flex flex-row">\n`;
for (let s = 0; s < gridSize; s++) {
let square = `\t\t<div class="square squares" id="square${i}" onclick="addColour(${i})"></div>\n`
if (requirement) {
square = `\t\t<div class="square squares" id="${i}"></div>\n`;
}
gridRow += square;
}
gridRow += `\t</div>\n`;
grid += gridRow; // this line
}
}
grid += `</div>\n`;
return grid;
}
console.log(generateGrid(true))

Related

javascript button on clock

Now I have issue that only first clicked button works when pressing others post buttons after first clicked button, it just disappears and not loading comments,
Adding snipped to clarify issue. It's first time using this feature. Sorry for issues, may you can help me with that.
I'm using django as backend.
var currentItems = 0;
function loadcomments(d) {
var post = d.getAttribute("data-post");
const elementList = document.querySelectorAll('#comment'+post);
for (let i = currentItems; i < currentItems + 2; i++) {
if (elementList[i]) {
elementList[i].style.display = 'block';
}
}
currentItems += 2;
if (currentItems >= elementList.length) {
event.target.style.display = 'none';
}
}
.comment {
display: none;
}
<div class='post'>
<div class='comment' id="comment1">
11
</div>
<div class='comment' id="comment1">
12
</div>
<div class='comment' id="comment1">
13
</div>
<div class='comment' id="comment1">
14
</div>
<div class='comment' id="comment1">
15
</div>
<a class="loadmore" href="javascript:void(0)"
onclick="loadcomments(this)" data-post="1">Load more</a>
</div>
<div class='post'>
<div class='comment' id="comment2">
21
</div>
<div class='comment' id="comment2">
22
</div>
<div class='comment' id="comment2">
23
</div>
<a class="loadmore" href="javascript:void(0)"
onclick="loadcomments(this)" data-post="2">Load more</a>
</div>
You need to set special currentItems variable for each posts.
remove the global currentItems variable and Try
function loadcomments(d) {
var post = d.getAttribute("data-post");
var currentItems = d.getAttribute("data-currentItems") | 0;
const elementList = document.querySelectorAll('#comment'+post);
for (let i = currentItems; i < currentItems + 2; i++) {
if (elementList[i]) {
elementList[i].style.display = 'block';
}
}
currentItems += 2;
d.setAttribute("data-currentItems", currentItems);
if (currentItems >= elementList.length) {
event.target.style.display = 'none';
}
}
As Teemu mentioned, "You've to declare and initialize currentItems outside of the function".
var currentItems = 0;
function loadcomments(d) {
var post = d.getAttribute("data-post");
const elementList = document.querySelectorAll('#comment'+post);
for (let i = currentItems; i < currentItems + 2; i++) {
if (elementList[i]) {
elementList[i].style.display = 'block';
}
}
currentItems += 2;
if (currentItems >= elementList.length) {
event.target.style.display = 'none';
}
}
div {
display: none;
}
<div id="comment1">
1
</div>
<div id="comment1">
2
</div>
<div id="comment1">
3
</div>
<div id="comment1">
4
</div>
<div id="comment1">
5
</div>
<a class="loadmore" href="javascript:void(0)" onclick="loadcomments(this)" data-post="1">Load more</a>

In my React.js project i Used some code in the JS file to add slider on my web page TypeError: Cannot read property 'style' of undefined

I am facing this actually I do not understand the actual error is where and which terms I am missing.
I have tried to fix it out, in the console at chrome browser, it locates an error at the started marked line I have given in my snippet.
slide[current].style.display = 'block'; this is actual line I found in the browser getting error
export default function Slider() {
let slide = document.querySelectorAll('.slide');
var current = 0;
function cls(){
for(let i = 0; i < slide.length; i++){
slide[i].style.display = 'none';
}
}
function next(){
cls();
if(current === slide.length-1) current = -1;
current++;
**slide[current].style.display = 'block';**
slide[current].style.opacity = 0.4;
var x = 0.4;
var intX = setInterval(function(){
x+=0.1;
slide[current].style.opacity = x;
if(x >= 1) {
clearInterval(intX);
x = 0.4;
}
}, 100);
}
function prev(){
cls();
if(current === 0) current = slide.length;
current--;
slide[current].style.display = 'block';
slide[current].style.opacity = 0.4;
var x = 0.4;
var intX = setInterval(function(){
x+=0.1;
slide[current].style.opacity = x;
if(x >= 1) {
clearInterval(intX);
x = 0.4;
}
}, 100);
}
function start(){
cls();
slide[current].style.display = 'block';
}
start();
return (
<div>
<div class="container">
<div class="arrow l" onclick="prev()">
<img src={s1.jpg} alt="l" />
</div>
<div class="slide slide-1">
<div class="caption">
<h3>New York</h3>
<p>We love the Big Apple!</p>
</div>
</div>
<div class="slide slide-2">
<div class="caption">
<h3>Los Angeles</h3>
<p>LA is always so much fun!</p>
</div>
</div>
<div class="slide slide-3">
<div class="caption">
<h3>Bahar Dar</h3>
<p>Thank you, Bahar Dar!</p>
</div>
</div>
<div class="arrow r" onclick="next()">
<img src={s2.jpg} alt="r" />
</div>
</div>
</div>
)
}

JQuery Boostrap append row every 2 iterations but columns are ignored

I'm using JQuery 3 and Bootstrap 3. I'm trying to add dynamically row and col but I don't understand my error.
Every 2 iterations I want to add <div class="row"></div> in my dom and in this row I want to add 2 columns.
I'd like to get this HTML :
<div class="row">
<div class="col-xs-6">test</div>
<div class="col-xs-6">test</div>
</div>
<div class="row">
<div class="col-xs-6">test</div>
<div class="col-xs-6">test</div>
</div>
<div class="row">
<div class="col-xs-6">test</div>
</div>
But the current result what I get is :
<div class="row">
<div class="col-xs-6">test</div>
</div>
<div class="row">
<div class="col-xs-6">test</div>
</div>
I don't understand why some col are ignored. Here is my javascript code :
for (var i = 1; i < 5; i++) {
let row = $("<div>", {"class": "row"});
if (i % 2) {
$('.container').append(row);
}
let col = '<div class="col-xs-6">test</div>';
row.append(col);
}
And my jsfiddle : https://jsfiddle.net/gkn4vmx8/
Please try this
let row=null;
for (var i = 1; i < 5; i++) {
if (i % 2) {
row= $("<div>", {"class": "row"});
$('.container').append(row);
}
let col = '<div class="col-xs-6">test</div>';
row.append(col);
}
You can try this:
for (var i = 1; i < 5; i++) {
let row = $("<div>", {"class": "row"});
let col = '<div class="col-xs-6">test</div>';
if (i % 2) {
$('.container').append(row);
row.append(col);
}
row.append(col);
}
You have to reinitialize the row every 2 loops not every time so you can append on the same row to childs
let row;
for (var i = 1; i < 5; i++) {
if (i % 2) {
row= $("<div>", {"class": "row"});
$('.container').append(row);
}
let col = '<div class="col-xs-6">test</div>';
row.append(col);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container"></div>

Find duplicates by one of multiple classes

I have divs with multiple classes (brand and color) like:
<div id="pad">
<div class="bmw white"> </div>
<div class="porsche yellow"> </div>
<div class="porsche red"> </div>
<div class="bmw white"> </div>
<div class="bmw blue"> </div>
<div class="bmw white"> </div>
</div>
<div id="same"></div>
And when I need to know how many duplicate brands I have in #pad I use this code:
function sameCars() {
var elems = $("#pad div").length;
var brands = ['bmw', 'porsche'];
for (var i=0; i<brands.length; i++) {
var k = 0;
for (var j=0; j<elems; j++) {
var mainDiv = document.getElementById('pad'),
childDiv = mainDiv.getElementsByTagName('div')[j];
if(childDiv.className.split(' ')[0] == brands[i]) {
k = k+1;
}
}
addiv = document.getElementById("same");
addiv.innerHTML += brands[i] + ": " + k;
}
}
Now I want to make changes in my code:
1) to find duplicates for all classes (there could be more classes, first one is brand, the second one is color, etc) like bmw: 4, porsche: 2, white: 3, black: 3, sedan: 2, coupe: 3
2) not to use list of brands, colors, etc. I don't want to make a long list of all possible colors or car brands. Just get colors from classname
3) Make my code shorter and more elegant
You just have to dynamically gather all classes fists:
$(document).ready(function () {
var duplicates = {};
var $pad = $('#pad');
$('#pad > div').each(function () {
var classes = $(this)[0].classList;
for (var i = 0; i < classes.length; i++) {
if (typeof duplicates[classes[i]] === 'undefined') {
duplicates[classes[i]] = 1;
} else {
duplicates[classes[i]]++;
}
}
});
for (var j in duplicates) {
$pad.append('<div>'+j+':'+duplicates[j]+'</div>');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="pad">
<div class="bmw white"> </div>
<div class="porsche yellow"> </div>
<div class="porsche red"> </div>
<div class="bmw white"> </div>
<div class="bmw blue"> </div>
<div class="bmw white"> </div>
</div>
<div id="same"></div>
You can use jquery to get classes dynamically and apply logic to get unique counts like this.
sameCars();
function sameCars() {
var brands = [];
var colors = [];
$("#pad div").each(function(){
brands.push($(this).attr("class").split(' ')[0])
colors.push($(this).attr("class").split(' ')[1])
});
//console.log(brands)
//console.log(colors)
var cars_count = {};
$.each(brands, function( index, value ) {
cars_count[value] = cars_count[value] + 1 || 1;
});
console.log("Unique cars count :")
console.log(cars_count);
var count_color = {};
$.each(colors, function( index, value ) {
count_color[value] = count_color[value] + 1 || 1;
});
console.log("Unique Colors count :")
console.log(count_color);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="pad">
<div class="bmw white"> </div>
<div class="porsche yellow"> </div>
<div class="porsche red"> </div>
<div class="bmw white"> </div>
<div class="bmw blue"> </div>
<div class="bmw white"> </div>
</div>
<div id="same"></div>
Here is a nice way of getting what you want. Note I do not manipulate the DOM, I'll leave that up to you.
function classIsDup(className, setOfClasses)
{
return (setOfClasses.indexOf(className) > -1);
}
function getDuplicates()
{
var setOfClasses = [];
var listOfDuplicates = [];
$('#pad').children('div').each(function( index ) {
if(classIsDup($(this).attr('class'), setOfClasses))
{
listOfDuplicates.push($(this).attr('class'));
}
else
{
setOfClasses.push($(this).attr('class'));
}
});
// just in case dups exist within the list of dups
$.uniqueSort(listOfDuplicates);
}
getDuplicates();
Javascript example (no jquery required)
var parentWrapper = document.getElementById('pad');
var displayWrapper = document.getElementById('same');
var classesList = getUniqueClassList(parentWrapper);
displayCounts(classesList);
function displayCounts(list) {
for (var className in list) {
var number = list[className];
displayWrapper.innerHTML += className + ' ' + number + '<br>';
}
}
function getUniqueClassList(wrapper) {
var list = {};
for (var elem of wrapper.getElementsByTagName('div')) {
for (var cssClass of elem.classList) {
if (!list[cssClass]) {
list[cssClass] = 1;
} else {
list[cssClass]++;
}
}
}
return list;
}
Fiddle https://fiddle.jshell.net/r1rk1xL3/5/

Javascript only addEventListener to parent style both parent and child differently

Currently have a div that controls the width of an element as well as the background color. That div has a child div which has the content which is semi-transparent. Which is why I need the first div. So the background is solid.
Now, I added an event listener to the parent which expands the width of one and decreases the width of the other 2 so they all fit. However, when I click on the parent div I would like the child of that specific div to add a class and remove a class from the other 2. Which I can't seem to figure out. Here's the code. Sorry if my formatting is poor, first time posting on stack overflow and I've googled and searched everything for an answer and can't seem to find one.
var purchaseStepCont = document.querySelectorAll(".step-container");
var purchaseStep = document.querySelectorAll(".step");
for (var i = 0; i < purchaseStepCont.length; i++) {
purchaseStepCont[i].addEventListener("click", function() {
for (var i = 0; i < purchaseStepCont.length; i++) {
purchaseStepCont[i].classList.remove("stepContActive");
purchaseStepCont[i].classList.add("stepContDeactive");
this.classList.add("stepContActive");
this.classList.remove("stepContDeactive");
}
});
}
<div class="step-container">
<div class="step">
<h1>01.</h1>
<h3>words</h3>
<p>wods</p>
</div>
</div>
<div class="step-container">
<div class="step">
<h1>01.</h1>
<h3>words</h3>
<p>wods</p>
</div>
</div>
<div class="step-container">
<div class="step">
<h1>01.</h1>
<h3>words</h3>
<p>wods</p>
</div>
</div>
You're very close. But if you want to add the class to the .step, you need this.firstElementChild.classList.add(...) rather than this.classList.add(...) (since this will be the .step-container, not the .step; but the .step is its first element child). Or for more markup flexibility, you could use this.querySelector(".step").
You can also use just a single event handler function rather than recreating it in the loop:
var purchaseStepCont = document.querySelectorAll(".step-container");
var purchaseStep = document.querySelectorAll(".step");
function clickHandler() {
var thisStep = this.firstElementChild; // Or this.querySelector(".step") would be more flexible
for (var i = 0; i < purchaseStep.length; i++) {
if (purchaseStep[i] === thisStep) {
purchaseStep[i].classList.add("stepContActive");
purchaseStep[i].classList.remove("stepContDeactive");
} else {
purchaseStep[i].classList.remove("stepContActive");
purchaseStep[i].classList.add("stepContDeactive");
}
}
}
for (var i = 0; i < purchaseStepCont.length; i++) {
purchaseStepCont[i].addEventListener("click", clickHandler);
}
.stepContActive {
color: blue;
}
.stepContDeactive {
color: #ddd;
}
<div class="step-container">
<div class="step">
<h1>01.</h1>
<h3>words</h3>
<p>wods</p>
</div>
</div>
<div class="step-container">
<div class="step">
<h1>01.</h1>
<h3>words</h3>
<p>wods</p>
</div>
</div>
<div class="step-container">
<div class="step">
<h1>01.</h1>
<h3>words</h3>
<p>wods</p>
</div>
</div>
clickHandler could be a bit shorter if you don't need to support IE11:
function clickHandler() {
var thisStep = this.firstElementChild; // Or this.querySelector(".step") would be more flexible
for (var i = 0; i < purchaseStep.length; i++) {
purchaseStep[i].classList.toggle("stepContActive", purchaseStep[i] === thisStep);
purchaseStep[i].classList.toggle("stepContDeactive", purchaseStep[i] !== thisStep);
}
}
But IE11 doesn't support the second argument to classList.toggle.

Categories

Resources