Counter made by Javascript and did scrolling in it by using setInterval - javascript

Trying to make counter(till 9) by javascript.
Hid the counting of 1 to 9. So, when the user enters the target then scroll the counter by its height so the hidden numbers will be shown. Used two set intervals in the code maybe that's why code not running according to expectation.
codepen link --> https://codepen.io/aryansharma-2002/pen/GRyZJJv
same code pasted here:-
HTML CODE
<div class="input">
<h1 class="heading">Enter a value between 0 and 9</h1>
<div class="left">
<input type="number" id="count" placeholder="Enter Number">
</div>
<div class="right">
<button class="submit-btn" id="submit-btn">Start Counter</button>
</div>
</div>
<div class="output">
<div class="count-output" id="count-output">
<span class="zero" data-count="0">0</span>
<span class="one" data-count="1">1</span>
<span class="two" data-count="2">2</span>
<span class="three" data-count="3">3</span>
<span class="four" data-count="4">4</span>
<span class="five" data-count="5">5</span>
<span class="six" data-count="6">6</span>
<span class="seven" data-count="7">7</span>
<span class="eight" data-count="8">8</span>
<span class="nine" data-count="9">9</span>
</div>
</div>
NO NEED TO READ FULL CSS CODE. THE MAIN CSS is that to div.count-output is given some fixed height and width and then the span tag inside it, is giving 100% height and width so that only one number shown at a time. And all the other numbers is hidden by using overflow: hidden; css rule. So, we will scroll the .count-output by using javascript.
CSS CODE
#import url('https://fonts.googleapis.com/css2?family=Roboto:wght#300;400;500;700;900&display=swap');
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
font-family: 'Roboto', sans-serif;
}
.input{
width: 90%;
margin: 10px auto;
padding: 50px;
background: rgb(2,0,36);
background: linear-gradient(90deg, rgba(2,0,36,1) 0%, rgba(44,177,204,0.5374883229659051) 0%, rgba(255,0,218,0.32180204845610116) 100%);
}
.heading{
color: white;
word-spacing: 4px;
font-weight: 700;
margin-bottom: 25px;
text-align: center;
}
.left{
float: left;
width: 50%;
/* border: 2px solid black; */
text-align: center;
}
.right{
width: 50%;
float: right;
/* border: 2px solid black; */
text-align: center;
}
.input::after{
content: "";
display: block;
clear: both;
}
.input input[type="number"]{
width: 50%;
font-size: 20px;
padding: 3px 5px;
outline: none;
border: none;
}
.submit-btn{
background: white;
font-size: 18px;
font-weight: 700;
padding: 10px;
border: none;
border-radius: 15px;
box-shadow: 0px 0px 10px 0px white;
}
.output{
width: 80%;
margin: 20px auto;
background: rgba(0, 0, 0, 0.685);
height: 150px;
display: flex;
justify-content: center;
align-items: center;
}
.output .count-output{
/* border: 2px solid white; */
width: 75px;
/* height: 75px; */
height: 75px;
background: white;
box-shadow: 0px 0px 5px 0px white;
overflow: hidden;
}
.count-output span{
display: inline-block;
width: 100%;
height: 100%;
border-top: 2px solid red;
font-size: 70px;
/* text-align: center; */
display: flex;
justify-content: center;
align-items: center;
/* font-weight: 700; */
}
JS CODE
// when we click the submit button then take the data of the count, then start the counter and from 1 to 9 data hidden there so by js scroll it after 1sec when the target reaches stop and show alert
var input=document.getElementById("count");
var btn=document.getElementById("submit-btn");
var counter=document.getElementById("count-output");
console.log(input);
console.log(btn);
console.log(counter);
var scrollTillTarget=function (target) {
let count=0;
var heightCounter=counter.clientHeight;
console.log(heightCounter);
let intervalId=setInterval(function () {
if (count==target) {
alert("Target has reached");
clearInterval(intervalId);
counter.scrollTo(0,0);
return;
}
// By this line scrolling occurs instantly so the scrolling is not shown. So, used the setInterval so that do small scrolling in small time till the height of counter.
// counter.scrollBy(0,heightCounter);
let currentScroll=0;
let scrollId=setInterval(function () {
if (currentScroll==heightCounter) {
clearInterval(scrollId);
return;
}
counter.scrollBy(0,1);
currentScroll++;
},1);
count++;
},1000);
}
btn.addEventListener("click",function (event) {
var targetCount=input.value;
console.log(targetCount);
// now start the counter and scroll the count-output div to the span where the data-count attribute of span is equal to the targetCount
scrollTillTarget(targetCount);
});
Problem - Want that scrolling must show and also in 1 second. Then next scrolling till the target count.
This problem occuring maybe because the call stack is blocked by the setInterval callback function.
Solved this question by some other technique but want the answer why the above code is having some problem.
Solved Link- https://codepen.io/aryansharma-2002/pen/MWrjELL

Related

Copy text to clipboard with JS

I am a JS beginner and I have the following problem: I want that as soon as someone clicks on the URL icon inside the accordion the respective link is copied to the clipboard. Unfortunately (always) only the first link is copied to the clipboard, even if one clicks on the other two URL icons only the first link is copied. Although in the clipboard should be link 2 (from the value field) when i click on URL icon 2 (and the same for number 3 of course). I hope I have described the problem clearly enough.
Where is the error and what do I need to change on the JS code to make it work? Thanks a lot for the help in advance!
```
<!DOCTYPE html>
<html>
<head>
<title>My example Website</title>
<style>
body {
font-size: 21px;
font-family: Tahoma, Geneva, sans-serif;
max-width: 550px;
margin: 0 auto;
background-color: black;
}
input {
display: none;
}
label {
display: block;
padding: 8px 22px;
margin: 0 0 1px 0;
cursor: pointer;
background: #181818;
border: 1px solid white;
border-radius: 5px;
color: #FFF;
position: relative;
}
label:hover {
background: white;
border: 1px solid white;
color:black;
}
label::after {
content: '+';
font-size: 22px;
font-weight: bold;
position: absolute;
right: 10px;
top: 2px;
}
input:checked + label::after {
content: '-';
right: 14px;
top: 3px;
}
.content {
background: #DBEECD;
background: -webkit-linear-gradient(bottom right, #DBEECD, #EBD1CD);
background: -moz-linear-gradient(bottom right, #DBEECD, #EBD1CD);
background: linear-gradient(to top left, #DBEECD, #EBD1CD);
padding: 10px 25px 10px 25px;
border: 1px solid #A7A7A7;
margin: 0 0 1px 0;
border-radius: 1px;
}
input + label + .content {
display: none;
}
input:checked + label + .content {
display: block;
}
.whitepaper {
cursor: pointer;
text-align: center;
background-color: white;
border: 2px solid black;
border-radius: 3px;
float: left;
margin: 5px 5px 5px 0;
height: 40px;
width: 30px;
}
.blackframe {
text-align: center;
background-color: black;
cursor: pointer;
font-family: Tahoma, Geneva, sans-serif;
font-size:12px;
font-weight:bold;
margin: 12px 0 12px 0;
color: white;
width: 30px;
}
.whitepaper:hover {
cursor: pointer;
text-align: center;
background-color: black;
border: 2px solid white;
border-radius: 3px;
float: left;
margin: 5px 5px 5px 0;
height: 40px;
width: 30px;
}
/* Tooltip container */
.tooltip {
position: relative;
display: inline-block;
}
/* Tooltip text */
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
padding: 5px 0;
border-radius: 6px;
/* Position the tooltip text */
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -60px;
/* Fade in tooltip */
opacity: 0;
transition: opacity 0.3s;
}
/* Tooltip arrow */
.tooltip .tooltiptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
</style>
</head>
<body>
<input type="checkbox" id="title1" name="contentbox" />
<label for="title1">Content 1</label>
<div class="content">
<div class="tooltip"><div class="whitepaper" onclick="myFunction()"><div class="blackframe"><span class="tooltiptext">Copy link 1 to clipboard</span>URL</div></div><input type="text" value="https://mywebsite.com/#title1" id="myInput"></div>
</div>
<input type="checkbox" id="title2" name="contentbox" />
<label for="title2">Content 2</label>
<div class="content">
<div class="tooltip"><div class="whitepaper" onclick="myFunction()"><div class="blackframe"><span class="tooltiptext">Copy link 2 to clipboard</span>URL</div></div><input type="text" value="https://mywebsite.com/#title2" id="myInput"></div>
</div>
<input type="checkbox" id="title3" name="contentbox" />
<label for="title3">Content 3</label>
<div class="content">
<div class="tooltip"><div class="whitepaper" onclick="myFunction()"><div class="blackframe"><span class="tooltiptext">Copy link 3 to clipboard</span>URL</div></div><input type="text" value="https://mywebsite.com/#title3" id="myInput"></div>
</div>
<script>
function myFunction() {
/* Get the text field */
var copyText = document.getElementById("myInput");
/* Select the text field */
copyText.select();
copyText.setSelectionRange(0, 99999); /* For mobile devices */
/* Copy the text inside the text field */
navigator.clipboard.writeText(copyText.value);
/* Alert the copied text */
alert("Copied: " + copyText.value);
}
</script>
</body>
</html>
```
Replace function myFunction like this:
function myFunction(event) {
var target = event.target;
var copyText = target.nextElementSibling;
navigator.clipboard.writeText(copyText.value);
alert("Copied: " + copyText.value);
}
then update all onclick attributes like this
onclick="myFunction(event)"
I found a few issues with your code
You didn't change the id number on the inputs so they all would alert to the same URL which made it difficult to tell which is being clicked on.
You are doing a query selection on an id that appears multiple times. This means it is not being fired on the clicked element.
My approach includes taking advantage of the clicked element by passing it in your click handler.
<div class="tooltip">
<div class="whitepaper" onclick="myFunction(event)">
<div class="blackframe"><span class="tooltiptext">Copy link 3 to clipboard</span>URL</div>
</div><input type="text" value="https://mywebsite.com/#title3" id="myInput">
</div>
This lets me pass that event to the function call which will give us access to the current target node.
function myFunction(event) {
/* Get the text field */
var copyText = event.target.parentNode.nextSibling.nextSibling.value
/* Copy the text inside the text field */
navigator.clipboard.writeText(copyText);
/* Alert the copied text */
alert("Copied: " + copyText);
}
In the above case, I had to do some weird traversing because your input is outside the scope of the clicked element. I removed the code related to mobile stuff because that wasn't relevant to this issue (feel free to put that back in).
here's the codepen with my example.

CSS - Row content won't change size when window changes size

Row content won't change it size when window size decreased.
The problem is the style of every element - flex: 0 0 100px
Not growable (0), not shrinkable (0), and with an initial length of 100px
How can I replace this style to look the same, but will be responsive to window size decrease.
Now without the flex: 0 0 100px, it won't be in a straight line order, and each element won't be above next element's row
With array.map((obj, index) => {return ( <div but I made it here with only two elements.
codesandbox - two rows
If its better to look at it in the codesandbox please tell me and I'll delete the snippet code below.
.product-row {
background-color: rgba(202, 226, 245, 0.658);
border: 1px solid black;
border-bottom-width: 3;
border-top-width: 0;
border-left-width: 0;
}
.object-elements {
display: flex;
flex-direction: row;
}
.product-name {
box-sizing: border-box;
font-size: larger;
padding: 10px;
font-weight: 600;
flex: 0 0 210px;
}
.price {
font-size: larger;
padding: 10px;
font-weight: 600;
padding-left: 16px;
padding-right: 16px;
flex: 0 0 100px;
}
.quantity-button {
font-size: larger;
padding: 10px;
font-weight: 600;
flex: 0 0 160px;
}
.quantity {
display: inline-block;
width: 20px;
text-align: center;
}
.add-remove {
width: 3rem;
font-size: 1.5rem;
text-align: center;
text-shadow: 0 1px 0 rgba(#fff, 0.6);
cursor: pointer;
border-radius: 10px;
margin: 5px;
border-width: thin;
}
.total-price {
font-size: larger;
font-weight: 600;
padding: 10px 0px 0px 50px;
flex: 0 0 100px;
}
.product-img {
border: 1px solid black;
width: 100px;
height: 100px;
}
<div class="product-row">
<div class="object-elements">
<img src="https://image.freepik.com/free-vector/realistic-vitamin-complex-package_52683-35815.jpg" ' alt="" class="product-img" />
<div class="product-name">butterfly</div>
<div class="price"> 30$</div>
<div class="quantity-button">
<button class="add-remove">-</button>
<div class="quantity">23</div>
<button class ="add-remove">+</button>
</div>
<div class="total-price">230$</div>
</div>
</div>
In this snippet the "total price" is out of the row, not as in a full window.
Use rem to make HTML resize to the width of the device screen
The content overflows from the div.
To avoid that we need to provide padding on the right.
.product-row {
background-color: rgba(202, 226, 245, 0.658);
border: 1px solid black;
border-bottom-width: 3;
border-top-width: 0;
border-left-width: 0;
padding-right: 35rem;
}
And for the whole page to be responsive based on the width of the screen. Convert every px to rem.
If you want everything on the page to change its size based on the width. Then try converting font-size and widths to rems.
Check here for updated code.
Try adding max-width: 100px;, max-width: 100px;
so it does not expand or shrink but is responsive

Staggering chatbot queries and replies in GUI

I am working on a chatbot at the moment and trying to connect a GUI I have been working with to the project.
It is running smooth but my output is a little messed up; in particular, the chat boxes should alternate between the user and the BOT, but they are stacking on top and not formatting correctly.
I want to fix this issue, but keep the screen dividing in half down the middle so that the bot outputs are on the right and the users on the left. I just need to get them to alternate back and forth.
I've tried anchoring the newest box with a margin-top, tried setting a counter variable to update the placement of each new box, etc., but am having trouble spacing them relative to each other.
Below is the code without the backend work. So, this won't run perfect but it should get the setup I have across...
Here is the CSS code:
body {
font-family: Cambria;
color: rgb(122, 4, 4);
background-color: rgb(136, 175, 175);
}
h1 {
color: black;
margin-bottom: 0;
margin-top: 0;
text-align: center;
font-size: 40px;
}
h2 {
color: black;
font-size: 20px;
margin-top: 3px;
text-align: center;
}
#user_chatbox {
margin-left: 0;
margin-right: auto;
width: 50%;
margin-top: 30%;
}
#bot_chatbox {
margin-left: 50%;
margin-right: auto;
width: 50%;
margin-top: 10%;
/* height: 80%; */
/* background-color: pink; */
/* border-radius: 10px; */
}
#userInput {
margin-left: auto;
margin-right: auto;
width: 95%;
margin-top: 150px;
}
#textInput {
width: 92%;
border: 3px solid Black;
border-bottom: 3px solid #660096;
font-family: Cambria;
font-size: 16px;
}
#buttonInput {
padding: 10px;
font-family: Cambria;
font-size: 72;
}
.userText {
color: rgb(0, 0, 0);
font-family: Georgia;
font-size: 16px;
text-align: left;
line-height: 20px;
}
.userText span {
display:block;
width:auto;
background-color: rgb(87, 201, 152);
padding: 10px;
border-radius: 10px;
/* counter-increment: var(--chatbox_spacing); */
}
.botText {
color: Black;
font-family: Consolas, monaco, monospace;
font-size: 16px;
text-align: left;
/* line-height: calc(29 + var(--chatbox_spacing))px; */
line-height: 20px;
}
.botText span {
display:block;
width:auto;
background-color: rgb(73,196,199);
padding: 10px;
border-radius: 10px;
/* counter-increment: var(--chatbox_spacing); */
}
... and here are the .html with .js code (within index.html) that is updating the blocks to be printed out with new information (input from the user and a reply from the bot):
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/static/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<h1>Analysis Chatbot</h1>
<!-- The main chat environment for interacting with the bot. -->
<div>
<!-- The text of the bot. -->
<div id="bot_chatbox">
<p class="botText"><span>Welcome! How can I help you analyze your dataset?</span></p>
</div>
<div id="user_chatbox"></div>
<!-- The input text of the user interacting with the bot. -->
<div id="userInput">
<input id="textInput" type="text" name="msg" placeholder="Message">
<input id="buttonInput" type="submit" value="Send">
</div>
<script>
function getBotResponse() {
var rawText = $("#textInput").val();
var userHtml = '<p class="userText"><span>' + rawText + '</span></p>';
$("#textInput").val("");
$("#user_chatbox").append(userHtml);
document.getElementById('userInput').scrollIntoView({block: 'start', behavior: 'smooth'});
$.get("/get", { msg: rawText }).done(function(data) {
var botHtml = '<p class="botText"><span>' + data + '</span></p>';
$("#bot_chatbox").append(botHtml);
document.getElementById('userInput').scrollIntoView({block: 'start', behavior: 'smooth'});
});
}
$("#textInput").keypress(function(e) {
if(e.which == 13) {
getBotResponse();
}
});
$("#buttonInput").click(function() {
getBotResponse();
})
</script>
</div>
</body>
</html>
Nothing breaks, but I have attached some images below of the current output. Again, it isn't as much that the replies are basic right now, but rather that I want the displayed text blobs to be alternating from the bot (right side) to the user (left side) while keeping the screen split in the middle.
I want that image to be: the top blue on the right (Welcome...) then the first green on the left (can you find me sales in...) then next blue on right and so on so forth...
I put together a basic example of what you're trying to do using a 100% width wrapper that holds the message inside. The wrapper has display:flex; so that the <div>s inside don't expand. Check it out:
$(document).ready(function() {
$('#sendUser').click(function(){
if($('#userText').val()!=""){
$('#chatbox').append('<div class="message user"><div>'+$('#userText').val()+'</div></div>');
$('#userText').val('');
}
});
$('#sendBot').click(function(){
if($('#userText').val()!=""){
$('#chatbox').append('<div class="message bot"><div>'+$('#userText').val()+'</div></div>');
$('#userText').val('');
}
});
});
#chatbox{
width: 300px;
height: 400px;
border: 1px solid black;
margin: auto;
margin-top: 20px;
overflow-y: scroll;
}
#inputs{
display: grid;
padding: 10px 0;
width: 300px;
margin: auto;
grid-template-columns: auto 40px 40px;
grid-gap: 4px;
}
.button{
text-align: center;
border: 1px solid #a0a0a0;
cursor: pointer;
}
.button:hover{
background-color: grey;
color: white;
}
.message{
display: flex;
}
.message.user{
text-align: left;
}
.message > div{
margin: 10px 10px 0;
padding: 6px 8px;
border-radius: 15px;
color: white;
}
.message.bot > div{
margin-left: auto;
background-color: teal;
}
.message.user > div{
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chatbox">
<div class="message bot">
<div>
hello
</div>
</div>
<div class="message user">
<div>
hello!
</div>
</div>
</div>
<div id="inputs">
<input type="text" id="userText">
<div class="button" id="sendBot">Bot</div>
<div class="button" id="sendUser">User</div>
</div>
Here's the CodePen if you wanted to mess with it.

Some hr tags have gaps inside them while other doesn't

I have a pen, which is basically a todo app. The todo items are actually li elements which have text, button and a hr. Some of them are having hr with spaces inside them while some doesn't.
Image:
HTML:
const j = $;
j(() => {
let validify = txt => {
if (txt.length > 0) {
j('#ctn').append(`<li class='td'>${txt}<button class='td-btn'>Dismiss</button><hr/></li>`);
}
j('.td-btn').on('mouseenter', function() {
console.log('added');
j(this)
.parent()
.addClass('del');
console.log(j(this).parent().attr('class'))
}).on('mouseleave', function() {
console.log('removed')
j(this)
.parent()
.removeClass('del');
}).on('click', function() {
j(this).parent().css('display', 'none');
});
j('#addtd').val('');
}
validify('');
j('#btn').on('click', () => {
validify(j('#addtd').val());
});
});
#import url("https://fonts.googleapis.com/css?family=Lato");
* {
box-sizing: border-box;
font-family: Lato;
}
body {
margin: 0;
padding: 3vh 7vw;
background: #004D40;
}
#in-ctn {
position: fixed;
width: 86vw;
height: 16vh;
background: #388E3C;
box-shadow: 0 6px 9px #272727;
z-index: 2;
}
#btn {
position: absolute;
border-radius: 100%;
outline: none;
border: none;
right: 7vh;
top: 3vh;
width: 10vh;
height: 10vh;
font: 500 8vh arial;
display: inline-block;
transition: 0.25s all;
background: #CDDC39;
}
#btn:hover {
box-shadow: 0 2px 1px rgba(0, 0, 0, 0.33);
transform: scale(1.1);
}
#btn:active {
transform: translateY(4px);
}
#addtd {
position: absolute;
outline: none;
border: none;
background: rgba(255, 255, 255, 0.33);
width: 50vw;
height: 6vh;
top: 5vh;
left: 5vw;
font: 500 14pt Lato;
padding: 0 10px;
}
#addtd::placeholder {
color: #FFF;
}
#ctn {
position: absolute;
top: 27vh;
width: 86vw;
background: #388E3C;
box-shadow: 0 6px 9px #272727;
padding: 3vh 5vw;
z-index: 1;
}
li.td {
font: 500 20pt Lato;
list-style: none;
color: #FFF;
}
button.td-btn {
float: right;
outline: none;
border: none;
background: #E53935;
height: 20px;
position: relative;
top: 25px;
color: #FFF;
}
hr {
border: 7px solid #9E9D24;
padding: 0;
}
.del {
color: #CDDC39 !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='main'>
<div id='in-ctn'>
<button id='btn'>+</button>
<input type='text' id='addtd' placeholder='Enter a new Todo' />
</div>
<div id='ctn'>
<li class='td'>
Code a Todo App
<button class='td-btn'>Dismiss</button>
<hr/>
</li>
<li class='td'>
Style the Elements
<button class='td-btn'>Dismiss</button>
<hr/>
</li>
<li class='td'>
Debug some problems
<button class='td-btn'>Dismiss</button>
<hr/>
</li>
<li class='td'>
Go for a walk
<button class='td-btn'>Dismiss</button>
<hr/>
</li>
</div>
</div>
Can anyone explain me why it is so?
This is happening due to CSS Sub pixel rendering.
When you zoom-in/out of the browser, the rescaled elements will have left over pixel values like 5.75px etc. The vendor decides how to deal with that.
In your case the easiest fix, at least in Chrome, is to cancel the border radius to 0px, instead set the height of the hr to double the border and give it a background color:
border: 0px solid #9E9D24;
padding: 0;
height: 14px;
background: #9E9D24;
Seems like this issue is browser related, since it works fine for most people. Possibly your browser has a default styling for hr elements. It is, however, nowadays bad practice to use a horizontal line for presentational terms. Source
You would be fine by using a border-bottom on your li element. If you want to position the border lower than the default position, you can use padding-bottom on the li element. Your HTML structure also looks a lot more clear with this.
For example, changing the styling of your CSS selector li.td to the following could do the trick:
li.td {
font: 500 20pt Lato;
list-style: none;
color: #CDDC39;
border-bottom: 10px solid #9E9D24;
padding-bottom: 10px;
margin-bottom: 10px;
}
In case you really need to use the hr element, you could attempt to remove all default margin since some browsers add a margin by default. For that, add the following styling to the element:
margin: 0
which would result into
hr {
border: 7px solid #9E9D24;
padding: 0;
margin: 0;
}
Did you edit your pen to fix the issue? When looking at your pen preview all <hr> tags are rendered without an empty space inside.
The only suggestion I have, is that in HTML <hr> doesn't need to be explicitly closed, unless you are using XHTML, then you need to properly close the tag <hr />. Since you are just writing HTML, I would go with the <hr>.

`transitionend` stops firing after several events

I have a tricky problem. When a user presses on a div I want to add a css class to that div with name .active, using css transition. Then, after a short timeout, I want to handle transitionend event where I will remove the class .active from the div. The problem is, if a user presses on the button too fast, say 15-20 times per second, transitionend eventually stops firing.
You can see this effect here(clickable link), open Chrome browser(I wasn't able to reproduce it in FF) and start clicking on the button as fast as you can. After 15-20 clicks transitionend will stop triggering.
I think, when transitionend handler is still working, a user can press the button once again and the div will get .active class, but it will not trigger transition event. The question is - is it possible to write bullet-proof code to clear the .active class using transitionend event only ?
Thank you.
*edit* embedded snippet below
var blk = document.querySelector('.animated-element');
var btn = document.querySelector('.button');
var ctr = document.querySelector('.click-counter');
var lgr = document.querySelector('.logger');
btn.addEventListener('click', function() {
var currentValue = Number(ctr.innerHTML);
ctr.innerHTML = ++currentValue;
if (!blk.classList.contains('active')) {
blk.classList.add('active');
}
});
blk.addEventListener('transitionend', function() {
blk.classList.remove('active');
var li = document.createElement('li');
li.innerHTML = 'Transition end';
lgr.appendChild(li);
});
.scene {
position: relative;
width: 300px;
height: 300px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.animated-element {
width: 200px;
height: 200px;
margin-bottom: 10px;
display: flex;
justify-content: center;
align-items: center;
font-size: 2em;
background-color: #ff0000;
color: white;
border-radius: 5px;
transition: all 500ms;
}
.animated-element.active {
font-weight: 700;
/* background-color: #ff0055; */
}
.button {
padding: 5px 10px;
border: 2px solid black;
border-radius: 5px;
text-align: center;
cursor: pointer;
user-select: none;
}
.click-counter {
position: absolute;
top: 0;
left: 0;
min-height: 17px;
min-width: 17px;
padding: 2px 4px;
color: gray;
font-weight: bold;
text-align: center;
border: 2px solid gray;
border-radius: 50%;
user-select: none;
}
.logger {
width: 300px;
padding: 0;
list-style: none;
text-align: center;
}
<body>
<main>
<div class="scene">
<div class="click-counter">0</div>
<div class="animated-element">
<span>ABC</span>
</div>
<div class="button">
Press me several times
</div>
</div>
<ul class="logger"></ul>
</main>
</body>

Categories

Resources