How can I add css transition to elements Javascript created? - javascript

I'm trying to make a randomly placed puzzle with clicking, but it looks too rigid without any transition. I want to make the shuffle movement smoother with some delay or some transitions, so I tried to add CSS transition in each list item, but it doesn't really change anything. This is what I tried. How can I add CSS property to elements JS created?
<div class="wrap-all">
<ul class="image-container">
</ul>
</div>
<div class="container"></div>
<script>
const container = document.querySelector(".image-container");
const wrapAll = document.querySelector(".wrap-all");
const tileCount = 16;
let tiles = [];
setGame();
function setGame() {
tiles = createImageTiles();
tiles.forEach(tile => container.appendChild(tile));
}
wrapAll.addEventListener('click', () => {
const li = document.querySelector("li");
li.style.transitionDelay = "2s";
shuffle(tiles).forEach(tile => container.appendChild(tile));
setTimeout(() => {
container.innerHTML = "";
setGame();
}, 3000)
})
function createImageTiles() {
const tempArray = [];
Array(tileCount).fill().forEach((_, i) => {
const li = document.createElement("li");
li.setAttribute('data-index', i)
li.classList.add(`list${i}`);
tempArray.push(li)
})
return tempArray;
}
function shuffle(array) {
let index = array.length - 1;
while (index > 0) {
const randomIndex = Math.floor(Math.random() * (index + 1));
[array[index], array[randomIndex]] = [array[randomIndex], array[index]]
index--;
}
return array;
}
</script>

To add CSS transition to elements created by JavaScript, you need to add the transition property to the CSS style of the element. In your case, you can add the transition property to the "li" element style in the createImageTiles() function like this:
<div class="wrap-all">
<ul class="image-container">
</ul>
</div>
<div class="container"></div>
<script>
const container = document.querySelector(".image-container");
const wrapAll = document.querySelector(".wrap-all");
const tileCount = 16;
let tiles = [];
setGame();
function setGame() {
tiles = createImageTiles();
tiles.forEach(tile => container.appendChild(tile));
}
wrapAll.addEventListener('click', () => {
// select all "li" elements
const liList = document.querySelectorAll("li");
// add delay to transition for all "li" elements
liList.forEach(li => li.style.transitionDelay = "0.2s");
shuffle(tiles).forEach(tile => container.appendChild(tile));
setTimeout(() => {
container.innerHTML = "";
setGame();
}, 3000)
})
function createImageTiles() {
const tempArray = [];
Array(tileCount).fill().forEach((_, i) => {
const li = document.createElement("li");
li.setAttribute('data-index', i)
li.classList.add(`list${i}`);
// add transition property to "li" element
li.style.transition = "all 0.5s ease-in-out";
tempArray.push(li)
})
return tempArray;
}
function shuffle(array) {
let index = array.length - 1;
while (index > 0) {
const randomIndex = Math.floor(Math.random() * (index + 1));
[array[index], array[randomIndex]] = [array[randomIndex], array[index]]
index--;
}
return array;
}
</script>

Related

Carousel with dynamic images

Hello I want to implement a carousel in Java Script.
When I launch the page the image loads very strangely and the bootstrap carousel does not work. Do I need to import something to make it work? If I make it static in HTML it works. However the task is to load the images with iiif. Also, there would be way too many images to make it static. Also, I would like to have a filter function implemented which only works dynamically.
Can someone help me how to implement the carousel?
Here is all the JS code:
'import bootstrap.js'
function changeIIIFInformation(iiif, size, quality) {
var index = iiif.indexOf('full')
iiif = iiif.substring(0, index)
iiif += "full/"
iiif += "pct:" +size.toString() +"/"
iiif += "0/"
iiif += quality +".jpg"
return iiif
}
function search_period(period, max_num, offset) {
var count = 0;
var link = ""
var div = document.createElement('div')
var div1 = document.createElement ('div')
var a=document.createElement('a')
var span1=document.createElement('span')
var span2=document.createElement('span')
a.setAttribute('class','carousel-control-prev')
a.setAttribute('href','#carouselExampleControls')
a.setAttribute('role','button')
a.setAttribute('data-slide','prev')
span1.setAttribute('class','carousel-control-prev-icon')
span1.setAttribute('aria-hidden', 'true')
span2.setAttribute('class','sr-only')
span2.innerHTML = 'Previous'
div.setAttribute('class', 'carousel slide')
div.setAttribute('data-ride', 'carousel')
div.setAttribute('id', 'carouselExampleControls')
div1.setAttribute('class','carousel-inner')
var h2 = document.createElement('h2')
var iiif = ""
h2.innerHTML = period
document.body.appendChild(h2)
const keys = Object.keys(urls);
for(const elem of keys) {
var label = urls[elem].label
for(const el of urls[elem].variants) {
if(el.label.includes('front')) {
iiif = el.url
}
}
if(!periods.hasOwnProperty(label)) {
continue;
}
if(periods[label] != period) {
continue;
}
if(count < offset) {
count+=1
continue
}
var div2= document.createElement ('div')
div2.setAttribute('class','carousel-item active')
link = changeIIIFInformation(iiif, 10, "default")
var figure = document.createElement('figure')
var figcaption = document.createElement('figcaption')
var linkToImage = document.createElement('a')
//linkToImage.setAttribute('#image', label)
linkToImage.setAttribute('href', 'annotator#'+label)
linkToImage.innerHTML = label
figcaption.appendChild(linkToImage)
var image = document.createElement('img')
image.setAttribute("id", "myimg");
image.setAttribute('src', link)
image.setAttribute('class','d-block w-100')
// figure.appendChild(image)
// figure.appendChild(figcaption)
div.appendChild(div1)
div.appendChild(a)
div1.appendChild(div2)
a.appendChild(span1)
a.appendChild(span2)
div2.appendChild(image)
figure.setAttribute("id", "myFigure");
count += 1;
if(count >= max_num+offset) {
break;
}
}
document.body.appendChild(div)
}
function clear_dom() {
var elements = document.getElementsByTagName('div')
var headings = document.getElementsByTagName('h2')
var buttons = document.getElementsByTagName('button')
while(buttons.length > 0) {
buttons.item(0).remove()
}
while(elements.length > 0) {
elements.item(0).remove()
}
while(headings.length > 0) {
headings.item(0).remove()
}
}
function show_initial_load() {
search_period('Ur III (ca. 2100-2000 BC)', )
}
function show_filtered(selected, offset) {
clear_dom()
search_period(selected, 10, offset)
var previous = document.createElement('button')
if(offset-10 < 0) {
previous.onclick = () => show_filtered(selected, 0)
} else {
previous.onclick = () => show_filtered(selected, offset-10)
}
previous.innerHTML = 'Previous'
document.body.appendChild(previous)
var next = document.createElement('button')
next.onclick = () => show_filtered(selected, offset+10)
next.innerHTML = 'More'
document.body.appendChild(next)
}
function update_view() {
var selected = document.getElementById('perriod-select').value
clear_dom()
if(selected == '') {
show_initial_load()
} else {
show_filtered(selected, 0)
}
}

I Read using QuerySelectall.. how to write in innerhtml of these read tags?

I have degrees in Celsius switched them to Fahrenheit and cannot write them back to page.. picked them up with this statement
temp = document.querySelectorAll(".mylist span");
x=[]
for (let i = 0; i < temp.length; i++) {
temp[i].style.backgroundColor = "red";
x[i] = Number(temp[i].innerHTML);
Cannot write them back same way... Does not work
You need to set the innerHTML/textContent of the element with the new value.
const spans = document.querySelectorAll('#mylist span');
function CToF(v) {
return v * 9/5 + 32;
}
setTimeout(() => {
spans.forEach(span => {
const { textContent } = span;
span.classList.add('red');
span.textContent = CToF(textContent);
});
}, 2000);
.red { color: red; }
<div id="mylist">
<span>10</span>
<span>40</span>
<span>90</span>
</div>

Style all Elements of a div created via .createElement('div')

So I'm creating multiple new child divs inside another parent div with this code:
var parentDiv = document.querySelector('.parent-div')
const newDiv = document.createElement('div');
parentDiv.appendChild(newDiv);
So now I want to add an onlick event for every div I created, that resets the color for every other div inside the parent div, so that no multiple child divs are selected, and then set the color only for the clicked div to another color!
Any ideas?
var parentDiv = document.querySelector('.parent-div');
for (let i = 0; i < 10; ++i) {
const newDiv = document.createElement('div');
newDiv.className = "my-class";
newDiv.innerText = `Foo${i}`;
parentDiv.appendChild(newDiv);
}
parentDiv.onclick = (event) => {
document.querySelectorAll('.my-class').forEach((el) => {
el.className = "my-class";
});
event.target.className += " active";
}
.my-class {
color: red;
}
.active {
color: blue;
}
<div class="parent-div"></div>
let parentDiv = document.querySelector('.parent-div');
for (let x = 0; x < 10; x++) {
let newDiv = document.createElement('div');
newDiv.classList.add('see')
parentDiv.appendChild(newDiv);
}
parentDiv.addEventListener('click', (e) => {
if (e.target.tagName === 'DIV') {
e.target.style.backgroundColor = 'red';
}
})
Just to suggest a more robust and flexible way:
// Utility functions
const EL = (sel, EL) => (EL||document).querySelector(sel);
const ELS = (sel, EL) => (EL||document).querySelectorAll(sel);
const ELNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
// Now...
// Get element (Use an ID, not a class)
const EL_parent = EL('#parent');
// Function to toggle "is-active" class
const toggleActive = (EL_target, EL_parent) => {
const EL_active = EL(".is-active", EL_parent);
if (EL_active) EL_active.classList.remove("is-active");
EL_target.classList.add("is-active");
};
// Function to create new child elements
const newChild = (content) => ELNew("div", {
className: "child",
innerHTML: content,
onclick() {
toggleActive(this, EL_parent);
}
});
// Create a couple of elements....
EL_parent.append(
newChild("1 Lorem"),
newChild("2 Ipsum"),
newChild("3 Dolor"),
);
.is-active {
background: gold;
}
<div id="parent"></div>
So just a better way, and to avoid sloppy code like className = or Event.target without the use of .closest(), as shown in the other answers.
I'm not sure if this is how you would want to do it for many reasons, but it might be beneficial for you to change the HTML value of the parent div. For example,
var parentDiv = document.querySelector('.parent-div')
parentDiv.innerHTML = parentDiv.innerHTML + "<div class='{class name}'></div>";
The approach proposed here is aware of which div was clicked the last time, changes its style accordingly and creates the onclick when the item is created.
var parentDiv = document.querySelector('.parent-div');
let lastDiv = undefined;
for (let i = 0; i < 10; i++) {
let newDiv = document.createElement('div');
newDiv.style.width = "100px";
newDiv.style.height = "100px";
newDiv.style.backgroundColor = "black";
newDiv.style.border = "1px solid white";
newDiv.onclick = function() {
if (lastDiv) lastDiv.style.backgroundColor = "black";
newDiv.style.backgroundColor = "green";
lastDiv = newDiv;
};
parentDiv.appendChild(newDiv);
}
<div class="parent-div"></div>

How to remove all of the divs? with Vanilla JS

When I want to change the grid, I want the old one to disappear but right now the old one is being added to the new one. So how to remove all of the old divs? https://codepen.io/diana-larussa/pen/RwGMxqL
if (gridDOMElement.value === 'second') {
const elementsCount = 36
for (let index = 0; index < elementsCount; index++) {
const div = document.createElement("div")
container.appendChild(div)
}
container.style.gridTemplateColumns = "repeat(6, 7vmax)"
container.style.gridTemplateRows = "repeat(6, 7vmax)"
}
if (gridDOMElement.value === "third") {
const elementsCount = 70
for (let index = 0; index < elementsCount; index++) {
const div = document.createElement("div")
container.appendChild(div)
}
container.style.gridTemplateColumns = "repeat(10, 7vmax)"
container.style.gridTemplateRows = "repeat(7, 7vmax)"
}
}
document.querySelector("#grid").addEventListener("change", newGrid)```
I added this inside of the newGrid() function and it helped:
const item = document.querySelector('.container')
while (item.firstChild) {
item.removeChild(item.firstChild)
}

Add class by clicking and remove it at the next click

I built an app which add a class when i click on specified element. I want to add an additional functionality to my app. When i will click on an item i want to add my class clicked ( now the app works in the same way), but when i will click on another item i want to add the class on the last item and to remove the class from the first item.
document.addEventListener("DOMContentLoaded", () => {
const list = document.querySelectorAll('.item');
for (let i = 0; i < list.length; i++) {
list[i].addEventListener('click', function (e) {
const curentItem = e.target;
if (curentItem) {
curentItem.classList.add('clicked');
console.log(curentItem)
}
})
}
});
const arr = [1, 2, 3, 4]
const mapping = arr.map(item => `<li class="item">${item}</li>`);
document.querySelector('.items').innerHTML = mapping.join(' ');
.clicked {
background-color: blue;
}
<div class="app">
<ul class="items">
</ul>
</div>
How to change my code to get the specified result?
You can loop through list and remove class from each item and then add to the last item
document.addEventListener("DOMContentLoaded", () => {
const list = document.querySelectorAll('.item');
for (let i = 0; i < list.length; i++) {
list[i].addEventListener('click', function (e) {
const curentItem = e.target;
if (curentItem) {
list.forEach(item => item.classList.remove('clicked'))
curentItem.classList.add('clicked');
console.log(curentItem)
}
})
}
});
const arr = [1, 2, 3, 4]
const mapping = arr.map(item => `<li class="item">${item}</li>`);
document.querySelector('.items').innerHTML = mapping.join(' ');
.clicked {
background-color: blue;
}
<div class="app">
<ul class="items">
</ul>
</div>
Further more you shouldn't create html element using innerHTML and after that use
querySelectorAll() and select the elements.
A better and clean way for same functionality is like.
const ul = document.querySelector('.items');
const listItems = [];
document.addEventListener("DOMContentLoaded", () => {
initalizeItems([1, 2, 3, 4])
});
function initalizeItems(items){
items.forEach(text => {
const li = document.createElement('li');
li.innerHTML = text;
li.addEventListener('click', onItemClick)
listItems.push(li);
ul.appendChild(li)
})
}
function onItemClick(){
listItems.forEach(item => item.classList.remove('clicked'));
this.classList.add('clicked');
}
.clicked {
background-color: blue;
}
<div class="app">
<ul class="items">
</ul>
</div>
Just remove the class white looping all items inside the click event listner :
.....
for (let i = 0; i < list.length; i++) {
list[i].classList.remove('clicked');
.....
document.addEventListener("DOMContentLoaded", () => {
const list = document.querySelectorAll('.item');
for (let i = 0; i < list.length; i++) {
list[i].addEventListener('click', function (e) {
for (let i = 0; i < list.length; i++){
list[i].classList.remove('clicked');
// querySelectorAll return an array of dom elements, u can access them directly.
}
const curentItem = e.target;
if (curentItem){
curentItem.classList.add('clicked');
console.log(curentItem)
}
})
}
});
const arr = [1, 2, 3, 4]
const mapping = arr.map(item => `<li class="item">${item}</li>`);
document.querySelector('.items').innerHTML = mapping.join(' ');
.clicked {
background-color: blue;
}
<div class="app">
<ul class="items">
</ul>
</div>
Just use Element.classList.toggle, and as a boolean (toggle takes an optional second argument that basically says add if true, and remove if false), pass currentlyIteratedItem === clickedItem:
document.addEventListener("DOMContentLoaded", () => {
const list = document.querySelectorAll('.item');
for (const listItem of list) {
listItem.addEventListener('click', function(e) {
const clickedItem = e.target;
for (const currentlyIteratedItem of list) {
currentlyIteratedItem.classList.toggle('clicked', currentlyIteratedItem === clickedItem);
}
})
}
});
const arr = [1, 2, 3, 4]
const mapping = arr.map(item => `<li class="item">${item}</li>`);
document.querySelector('.items').innerHTML = mapping.join(' ');
.clicked {
background-color: blue;
}
<div class="app">
<ul class="items">
</ul>
</div>

Categories