I have a block, when changing dynamic height. Open animation works correct, but when im closing block, animation drops, cant undestand why.
Link: dev.divisory.com/6/
code example:
let linetags_more = (e) => {
clearTimeout(timer);
let container = e.target.closest(".js-line-tags");
let spc = e.target.closest(".js-line-tags").querySelector(".line-tags__wrap").clientHeight;
const box = container.querySelector(".line-tags__box");
if(container.classList.contains("js-line-tags__more--active")) {
container.classList.remove("js-line-tags__more--active");
box.style.maxHeight = spc+"px";
timer = setTimeout(() => {
box.style.maxHeight = row+"px";
}, 100);
} else {
box.style.maxHeight = spc+"px";
timer = setTimeout(() => {
container.classList.add("js-line-tags__more--active");
box.removeAttribute("style");
}, 200);
}
e.preventDefault();
}
The problem is box.removeAttribute("style"). Just remove it and everything going to be OK.
if (container.classList.contains("js-line-tags__more--active")) {
container.classList.remove("js-line-tags__more--active");
box.style.maxHeight = spc + "px";
timer = setTimeout(() => {
box.style.maxHeight = "60" + "px";
}, 100);
} else {
box.style.maxHeight = spc + "px";
timer = setTimeout(() => {
container.classList.add("js-line-tags__more--active");
//box.removeAttribute("style");
}, 200);
}
Related
I have an eventListener added to the window that activates code that takes 1000ms to run. Because of this, if you click again in less than 1000ms, it breaks. How can I disable the eventListener from running again within 1000ms of its previous invocation? I have a feeling it may have something to do with Date() but I'm not sure how to implement it.
Here's my code:
window.addEventListener("mousedown", event => {
let rememberContent = event.target.innerHTML;
if (event.target.classList.contains('color')) {
navigator.clipboard.writeText(event.target.dataset.hex);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
}, 1000)
} else {
navigator.clipboard.writeText(event.target.innerHTML);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
}, 1000)
}
})
I realize this question has been asked in multiple forms around the internet but I'm struggling to find a vanilla JS solution that works for me. That said, if an answer exists somewhere that I missed, feel free to point me in that direction!
It's called throttling, might be useful to search with that word
let working = false
window.addEventListener("mousedown", event => {
if (working) return
working = true
let rememberContent = event.target.innerHTML;
if (event.target.classList.contains('color')) {
navigator.clipboard.writeText(event.target.dataset.hex);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
working = false
}, 1000)
} else {
navigator.clipboard.writeText(event.target.innerHTML);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
working = false
}, 1000)
}
})
You can remove the listener and add it back after 1 second.
window.addEventListener("mousedown", handleClick)
function handleClick(event) {
let rememberContent = event.target.innerHTML;
if (event.target.classList.contains('color')) {
navigator.clipboard.writeText(event.target.dataset.hex);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
}, 1000)
} else {
navigator.clipboard.writeText(event.target.innerHTML);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
}, 1000)
}
window.removeEventListener("mousedown", handleClick);
setTimeout(() => window.addEventListener("mousedown", handleClick), 1000)
}
If you have a button, I recommend visually disabling it while the event listener is removed.
Maybe just add new variable that stores information about state of the process.
For example:
let isRunning = false;
window.addEventListener("mousedown", event => {
if (isRunning) return;
isRunning = true;
let rememberContent = event.target.innerHTML;
if (event.target.classList.contains('color')) {
navigator.clipboard.writeText(event.target.dataset.hex);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
isRunning = false;
}, 1000)
} else {
navigator.clipboard.writeText(event.target.innerHTML);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
isRunning = false;
}, 1000)
}
})
If isRunning is true, exit early.
You can set a global variable that controls whether or not clicks will fire your entire function. Then, you can pause events at the start of your function, and unpause events at the end of the wait period.
let pauseWindowEvent = false;
window.addEventListener("mousedown", event => {
if (pauseWindowEvent) return false;
pauseWindowEvent = true
let rememberContent = event.target.innerHTML;
if (event.target.classList.contains('color')) {
navigator.clipboard.writeText(event.target.dataset.hex);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
pauseWindowEvent = false;
}, 1000)
} else {
navigator.clipboard.writeText(event.target.innerHTML);
event.target.innerHTML = "<span>copied!</span>";
setTimeout(() => {
event.target.innerHTML = rememberContent;
pauseWindowEvent = false;
}, 1000)
}
})
I am new to programming and currently trying to build a timer. I am using JS when I encountered a problem on the very first line, it said that my function has already been declared when it hasn't. I read lots of other stack questions related to this error but none seems to have the same problem. Here is my code:
const timer = () => { // This is where the error occurs.
const song = document.querySelectorAll(".song");
const play = document.querySelector(".play");
const reset = document.querySelectorAll(".reset");
// Time display
const minuteDisplay = document.querySelectorAll(".minute");
const secondDisplay = document.querySelectorAll(".second");
//Duration
const formDuration = 20;
let duration = formDuration * 60;
let displayMinutes = ("0" + Math.floor(duration / 60)).slice(-2);
let displaySeconds = ("0" + Math.floor(duration % 60)).slice(-2);
for (const mdisplay in minuteDisplay) {
mdisplay.textContent = `${displayMinutes}`;
}
for (const sdisplay in secondDisplay) {
sdisplay.textContent = `${displaySeconds}`;
}
play.addEventListener("click", () => {
checkPlaying(song);
});
const checkPlaying = (song) => {
if (song.paused) {
song.play();
play.textContent = `Pause`;
play.classList.toggle("btn-active");
} else {
song.pause();
play.innerHTML = `Play`;
play.classList.remove("btn-active");
}
};
song.ontimeupdate = () => {
let currentTime = song.currentTime;
let elapsed = duration - currentTime;
let seconds = Math.floor(elapsed % 60);
let minutes = Math.floor(elapsed / 60);
// Edit time display
formatMinutes = ("0" + minutes).slice(-2);
formatSeconds = ("0" + seconds).slice(-2);
minuteDisplay.textContent = `${formatMinutes}`;
secondDisplay.textContent = `${formatSeconds}`;
reset.addEventListener("click", () => {
song.pause();
song.currentTime = 0;
play.innerHTML = `Play`;
play.classList.remove("btn-active");
if (reset.classList.contains("btn-active")) return;
reset.classList.add("btn-active");
// remove class after 2 seconds
setTimeout(() => {
reset.classList.remove("btn-active");
}, 150);
});
if (currentTime >= duration) {
song.pause();
song.currentTime = 0;
play.innerHTML = "Play";
play.classList.remove("btn-active");
}
};
};
timer();
I am confused as how to solve this error, so any feedback will be greatly appreciated. Thankyou!
Hi I checked your when you are using querySeelctorAll it returns array so before adding addEventListener you have to do for loop like this
let's do it for reset button:
const reset = document.querySelectorAll(".reset");
and now first for loop
reset.forEach(resetButton => {
resetButton.addEventListener("click", () => {
song.pause();
song.currentTime = 0;
play.innerHTML = `Play`;
play.classList.remove("btn-active");
if (reset.classList.contains("btn-active")) return;
reset.classList.add("btn-active");
// remove class after 2 seconds
setTimeout(() => {
reset.classList.remove("btn-active");
}, 150);
});
})
Or you can use loop like this:
for(const resetButton of reset) {
resetButton.addEventListener("click", () => {
song.pause();
song.currentTime = 0;
play.innerHTML = `Play`;
play.classList.remove("btn-active");
if (reset.classList.contains("btn-active")) return;
reset.classList.add("btn-active");
// remove class after 2 seconds
setTimeout(() => {
reset.classList.remove("btn-active");
}, 150);
});
}
Hope this would help.
And for debugging why "Uncaught SyntaxError: Identifier has already been declared error occurs" happens I need to have your HTML part too.
let me know when you updated the code
I am working on a whac a mole game where the background image should flash when the square is hit. For example an image that says "hit".
The square has been targeted correctly on function showImage(), tested with a console.log, and called in a forEach loop. I don't know the next step. I know I need to grab css class with background image of square and add an image. Maybe a set timer is involved. I have tried this and cannot get it working. See codepen
const squares = document.querySelectorAll('.square')
const mole = document.querySelector('.mole')
const timeLeft = document.querySelector('#time-left')
const score = document.querySelector('#score')
let result = 0
let hitPosition
let currentTime = 60
let timerId = null
function showImage() {
if ((document.onclick = squares)) {
squares.style.backgroundColor = 'green';
//console.log('it is working');
} else {
alert('it is not working');
}
}
function randomSquare() {
squares.forEach(square => {
square.classList.remove('mole')
})
let randomSquare = squares[Math.floor(Math.random() * 9)]
randomSquare.classList.add('mole')
hitPosition = randomSquare.id
}
squares.forEach(square => {
square.addEventListener('mousedown', () => {
if (square.id == hitPosition) {
result++
score.textContent = result
hitPosition = null
showImage();
}
})
})
function moveMole() {
timerId = setInterval(randomSquare, 500)
}
moveMole()
function countDown() {
currentTime--
timeLeft.textContent = currentTime
if (currentTime == 0) {
clearInterval(countDownTimerId)
clearInterval(timerId)
alert('GAME OVER! Your final score is ' + result)
}
}
let countDownTimerId = setInterval(countDown, 1000)
Sounds like this could handled by a class that displays an image in the background.
.bg-img {
background-image: url('');
}
And then in the function showImage() you set the class name bg-img on the element:
function showImage() {
squares.classList.add('bg-img');
setTimeout(function(){
squares.classList.remove('bg-img');
}, 1000);
}
And remove the class name again 1000 ms after.
I need help in improving the script for my background image slideshow.
I managed to create a fade in effect with .fadeIn(600) JS function. But, I want the images to switch between each other, not between white background.
In other words, I need to smooth up the transition between images.
Note that each image has a caption, but I'm OK with it as it is. I don't need any transitions for text.
JSFiddle http://jsfiddle.net/newsha/B4TXj/
var timer;
$(document).ready(function () {
// background image on load
var numberImages = 4
var images = [];
for (var i = 1; i <= numberImages; i++) {
images.push(i);
}
var imgValue = 1
$('.backgroundImage').addClass('bg' + imgValue + '');
// Switch background image - forwards
$('.imgSwitchRight').click(function () {
$('.backgroundImage').each(function (e) {
$(this).removeClass('bg1 bg2 bg3 bg4').fadeOut(0);
});
clearTimeout(timer);
timer = setTimeout(function () {
$('.imgSwitchRight').click();
}, 8000);
if (imgValue < numberImages) {
imgValue++
} else {
imgValue = 1
}
$('.backgroundImage').addClass('bg' + imgValue + '').fadeIn(600);
});
clearTimeout(timer);
timer = setTimeout(function () {
$('.imgSwitchRight').click();
}, 8000);
// Switch background - backwards
$('.imgSwitchLeft').click(function () {
$('.backgroundImage').each(function (e) {
$(this).removeClass('bg1 bg2 bg3 bg4').fadeOut(0);
});
clearTimeout(timer);
timer = setTimeout(function () {
$('.imgSwitchRight').click();
}, 8000);
if (imgValue > 1) {
imgValue--
} else {
imgValue = numberImages
}
$('.backgroundImage').addClass('bg' + imgValue + '').fadeIn(600);
});
clearTimeout(timer);
timer = setTimeout(function () {
$('.imgSwitchRight').click();
}, 8000);
});
I just used a secound div aas a swapping plane. the visible div is now fading out while the invisible one is fading in. after that the roles are switched and it goes on and on.. one problem still remains. if switching the images too fast the classes "stack" because the animation of the fading div is interrupted and the class will not be removed.. Problem solved..
var timer;
$(document).ready(function () {
// background image on load
var numberImages = 5,
easetime = 2000,
changetimeout = 5000;
var images = [];
for (var i = 1; i <= numberImages; i++) {
images.push(i);
}
var imgValue = 1;
var visibleBackground = $('.backgroundImage.a');
var invisibleBackground = $('.backgroundImage.b');
$('.backgroundImage').hide();
visibleBackground.addClass('bg' + imgValue + '').show();
var dir = 1;
function changeBG(){
oldValue = imgValue;
imgValue = (imgValue+dir)%numberImages;
$('.rotating-text'+imgValue).fadeIn(easetime);
$('.rotating-text'+oldValue).fadeOut(easetime);
clearTimeout(timer);
timer = setTimeout(function () {
changeBG();
}, changetimeout);
visibleBackground.fadeOut(easetime);
setTimeout(function(){
var tmpBackground = visibleBackground, tmpVal = oldValue;
return function(){
tmpBackground.removeClass('bg' + tmpVal)
}
}(), easetime);
invisibleBackground.addClass('bg' + imgValue + '').fadeIn(easetime);
var swap = visibleBackground;
visibleBackground = invisibleBackground;
invisibleBackground = swap;
}
// Switch background image - forwards
$('.imgSwitchRight').click(function () {
dir = 1;
changeBG()
});
// Switch background - backwards
$('.imgSwitchLeft').click(function () {
dir = -1;
changeBG()
});
timer = setTimeout(function () {
changeBG();
}, changetimeout);
});
http://jsfiddle.net/B4TXj/11/
Hi I have wrote this code and it suppose to move the object every 3000 ms after clicking on the object, but some how the time its not working, can anyone tell me what I am doing wrong, I am just learning javascript; thank you very much
function move1() {
var im1 = document.images[0];
im1.onclick = function() {
im1.style.left = parseInt(im1.style.left) + 1 + "px";
}
}
function move2() {
var im2 = document.images[1];
im2.onclick = function() {
im2.style.left = parseInt(im2.style.left) + 10 + "px";
}
}
window.onload = function() {
setInterval(move1, 100);
setInterval(move2, 3000);
}
You're doing it the other way round. Every 3000ms you make it possible to move the image by 1px when clicking on it.
function move(el, ms, px) {
/* moves the el every ms by px
returns the interval id to clear the movement */
return setInterval(function() {
el.style.left = parseInt(el.style.left) + px + "px";
}, ms);
}
window.onload = function() {
var im0 = document.images[0];
var im1 = document.images[1];
im0.onclick = function() {
move(im0, 100, 1);
};
im1.onclick = function() {
move(im1, 3000, 10);
};
}
Your move function registers the image on click, but doesn't actually do any moving until the user clicks. What you want is more like this:
function move1() {
var im1 = document.images[0];
im1.style.left = parseInt(im1.style.left) + 1 + "px";
}
function move2() {
var im2 = document.images[1];
im2.style.left = parseInt(im2.style.left) + 10 + "px";
}
window.onload = function() {
var im2 = document.images[1];
im2.onclick = function() {
setInterval(move2, 3000);
}
im1.onclick = function() {
setInterval(move1, 100);
}
}