setTimeout to JS function inside another one - javascript

I'm looking to add setTimeout to a JS function but inside this function I have another one, I'm aware that I can use onclick=setTimeout"(fooBar(), 2500);" but there's a loader inside my function, so to make it clear, I'd like to execute the function instantly (show loader div) when the button is clicked but setTimout to 2500 ms before running $.getJSON. Let's say I want to add a fake timeOut to the api request because that stuff is blazing fast.
Also, please let me know if my loading animation method with JS is ok, actually I think it's too much lines of code to show/hide div. I'm sure there's a better way to handle something like this. Thanks.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>JS Loader</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<style type="text/css" id="style">
#myloader {
position: relative;
left: 50%;
top: 50%;
z-index: 1;
width: 150px;
height: 150px;
margin: 25% -50;
border: 16px solid #000;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 120px;
height: 120px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Add animation to "page content" */
.animate-bottom {
position: relative;
-webkit-animation-name: animatebottom;
-webkit-animation-duration: 1s;
animation-name: animatebottom;
animation-duration: 1s
}
#-webkit-keyframes animatebottom {
from { bottom:-100px; opacity:0 }
to { bottom:0px; opacity:1 }
}
#keyframes animatebottom {
from{ bottom:-100px; opacity:0 }
to{ bottom:0; opacity:1 }
}
#myDiv {
display: none;
text-align: center;
}
</style>
<div class="container container-table">
<div class="row vertical-center-row">
<div class="col-md-4 col-md-offset-4">
<h1 id="name" >Real-time Bitcoin Price</h1>
<div id="myloader"style="display: none;"></div>
<p id="cointime"></p>
<div id="dollar"></div>
<div id="gbp"></div>
<div id="euro"></div><br>
<button id="refreshBtn" class="btn btn-primary">Load Data</button>
</div>
</div>
</div>
<script type="text/javascript">
document.getElementById("refreshBtn").addEventListener("click", function () {
var x = document.getElementById('myloader');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
$.getJSON("https://api.coindesk.com/v1/bpi/currentprice.json", function (data) {
var x = document.getElementById('myloader');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
$("#cointime").text(data.time.updated);
$("#dollar").text("USD : " + ' ' + data.bpi.USD.rate);
$("#gbp").text("GBP : " + ' ' + data.bpi.GBP.rate);
$("#euro").text("EUR :" + ' ' + data.bpi.EUR.rate);
})
});
</script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
</body>
</html>

To delay the AJAX request simply wrap the $.getJSON call in a setTimeout(). Also note that you're using an odd mix of jQuery and native JS functions. I'd suggest using one or the other, something like this:
$("#refreshBtn").on("click", function() {
$('#myloader').show();
setTimeout(function() {
$.getJSON("https://api.coindesk.com/v1/bpi/currentprice.json", function(data) {
$('#myloader').hide()
$("#cointime").text(data.time.updated);
$("#dollar").text("USD : " + ' ' + data.bpi.USD.rate);
$("#gbp").text("GBP : " + ' ' + data.bpi.GBP.rate);
$("#euro").text("EUR :" + ' ' + data.bpi.EUR.rate);
})
}, 2500);
});
#myloader {
position: relative;
left: 50%;
top: 50%;
z-index: 1;
width: 150px;
height: 150px;
margin: 25% -50;
border: 16px solid #000;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 120px;
height: 120px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* Add animation to "page content" */
.animate-bottom {
position: relative;
-webkit-animation-name: animatebottom;
-webkit-animation-duration: 1s;
animation-name: animatebottom;
animation-duration: 1s
}
#-webkit-keyframes animatebottom {
from {
bottom: -100px;
opacity: 0
}
to {
bottom: 0px;
opacity: 1
}
}
#keyframes animatebottom {
from {
bottom: -100px;
opacity: 0
}
to {
bottom: 0;
opacity: 1
}
}
#myDiv {
display: none;
text-align: center;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<div class="container container-table">
<div class="row vertical-center-row">
<div class="col-md-4 col-md-offset-4">
<h1 id="name">Real-time Bitcoin Price</h1>
<div id="myloader" style="display: none;"></div>
<p id="cointime"></p>
<div id="dollar"></div>
<div id="gbp"></div>
<div id="euro"></div><br>
<button id="refreshBtn" class="btn btn-primary">Load Data</button>
</div>
</div>
</div>
Also I'd suggest that adding a 2.5 second delay is far too much. I'm aware that adding a slight delay to make it more obvious that data has loaded is a good idea for UX, however I'd say that 500ms would be more than enough.

First - objects/elements:
You should always cache elements that you use more than once. Means: Assign an object to a variable that can be accessed everywhere you need it. Why? Because you can use the variable as often as you like. This saves much time and processing power because you don't need to look for an element with a certain id or class again and again. This is in my case the var x.
Second - the loader:
There are easy things like show() and hide() in jQuery, but I used ternary operation. Why? It is extremely flexible and I use it all day since I knew about it. So I want to show you this as a handy option :-).
Third - the timeout:
Pretty straight forward, wrap your function in a setTimeout() and there you go.
Here is a working fiddle:
EDIT: Now you could wrap the x.style.display lines in a separate function and call this so you can reuse the code and don't have to write it twice, but I think for demonstration purpose this should be fine.
var x = document.getElementById('myloader');
document.getElementById("refreshBtn").addEventListener("click", function () {
x.style.display = (x.style.display === 'none') ? 'block' : 'none';
setTimeout(function(){
$.getJSON("https://api.coindesk.com/v1/bpi/currentprice.json", function (data) {
x.style.display = (x.style.display === 'none') ? 'block' : 'none';
$("#cointime").text(data.time.updated);
$("#dollar").text("USD : " + ' ' + data.bpi.USD.rate);
$("#gbp").text("GBP : " + ' ' + data.bpi.GBP.rate);
$("#euro").text("EUR :" + ' ' + data.bpi.EUR.rate);
});
},2500);
});
#myloader {
position: relative;
left: 50%;
top: 50%;
z-index: 1;
width: 150px;
height: 150px;
margin: 25% -50;
border: 16px solid #000;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 120px;
height: 120px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Add animation to "page content" */
.animate-bottom {
position: relative;
-webkit-animation-name: animatebottom;
-webkit-animation-duration: 1s;
animation-name: animatebottom;
animation-duration: 1s
}
#-webkit-keyframes animatebottom {
from { bottom:-100px; opacity:0 }
to { bottom:0px; opacity:1 }
}
#keyframes animatebottom {
from{ bottom:-100px; opacity:0 }
to{ bottom:0; opacity:1 }
}
#myDiv {
display: none;
text-align: center;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container container-table">
<div class="row vertical-center-row">
<div class="col-md-4 col-md-offset-4">
<h1 id="name" >Real-time Bitcoin Price</h1>
<div id="myloader" style="display: none;"></div>
<p id="cointime"></p>
<div id="dollar"></div>
<div id="gbp"></div>
<div id="euro"></div><br>
<button id="refreshBtn" class="btn btn-primary">Load Data</button>
</div>
</div>
</div>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>

var timeout = null
function refresh () {
function load () {
$.getJSON('https://api.coindesk.com/v1/bpi/currentprice.json', function (data) {
$('#cointime').text(data.time.updated)
$('#dollar').text('USD : ' + data.bpi.USD.rate)
$('#gbp').text('GBP : ' + data.bpi.GBP.rate)
$('#euro').text('EUR : ' + data.bpi.EUR.rate)
timeout = null
})
}
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(load, 2500)
}
document.getElementById('refreshBtn').addEventListener('click', refresh)

Related

How can I show an element with Google Script when trying to make HTML spinner visible?

I am trying to show a spinning loader when a button is pushed. These have no impact:
document.getElementsByClass('loader')[0].style.visibility = 'visible';
document.getElementsByClass('loader').style.visibility = 'visible';
What am I doing wrong?
html code
<html>
<script>
function clickMe() {
document.getElementById('message').innerHTML = "mp";
document.getElementsByClass('loader')[0].style.visibility = 'visible';
google.script.run.withSuccessHandler(onSuccess).ChgNm();
}
function onSuccess(value){
document.getElementById('message').innerHTML= value;
}
</script>
<head>
<base target="_top">
</head>
<body>
<style>
.loader {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 60px;
height: 60px;
-webkit-animation: spin 2s linear infinite; /* Safari */
animation: spin 2s linear infinite;
}
/* Safari */
#-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<div class ='loader' visibility : hidden>Working</div>
<div id="message" style="color:green">test to unhide loader</div>
<p><button onclick="clickMe(); return false;">Look up my personal link</button></p>
</body>
Code
function doGet(e) {
return HtmlService
.createHtmlOutputFromFile('Index.html')
.setTitle("Hello World Example");//We can set title from here
}
function ChgNm(){
return "changed the name"
}
You have 2 mistakes.
getElementsByClass() is not a function. Replace it with getElementsByClassName() like this:
document.getElementsByClassName('loader')[0].style.visibility = 'visible';
visibility : hidden is a CSS property, so it is supposed to go inside the style attribute, like this:
<div class ='loader'style="visibility:hidden">Working</div>

How to fire "animationend" event, when I can't set a CSS animation?

If I set the css animation to "element", it's fine. If the Css animation is not available, how does it function fire like a zero seconds animation in the ES5?
function run() { ... }
element.addEventListener('animationend', run);
Reply for
#Anurag Srivastava,
Am I wrong idea or do I have the following code wrong? Either way, the return value is "".
var el1 = document.getElementById("notAnimation");
console.log(el1.style.animation);
var el2 = document.getElementById("onAnimation");
console.log(el2.style.animation);
div {
padding: 10px;
margin: 20px;
}
#notAnimation {}
#onAnimation {
animation: scale 10s ease-in-out;
}
#keyframes scale {
0% {
transform: scale(1);
opacity: 1;
color: black;
}
50% {
transform: scale(0.95);
opacity: .4;
color: red;
}
100% {
transform: scale(1);
opacity: 1;
color: black;
}
}
<div id="notAnimation">
Not Animation
</div>
<div id="onAnimation">
Animation
</div>
You can check if element.style.WebkitAnimation and element.style.animation contain any value and execute run() if the value is ""
Edit Turns out that .style will return "" for any value. What you need is window.getComputedStyle() along with the property animationName. If it is none, there is no animation, else there is. Check the code below:
var el1 = document.getElementById("notAnimation");
console.log(window.getComputedStyle(el1)["animationName"])
var el2 = document.getElementById("onAnimation");
console.log(window.getComputedStyle(el2)["animationName"])
div {
padding: 10px;
margin: 20px;
}
#notAnimation {}
#onAnimation {
animation: scale 10s ease-in-out;
}
#keyframes scale {
0% {
transform: scale(1);
opacity: 1;
color: black;
}
50% {
transform: scale(0.95);
opacity: .4;
color: red;
}
100% {
transform: scale(1);
opacity: 1;
color: black;
}
}
<div id="notAnimation">
Not Animation
</div>
<div id="onAnimation">
Animation
</div>

how to prevent from exiting or jump out elements from page?

I use several buttons to create motion, now i have a problem when i use marginLeft for move the element to left and right div#ball, it doesn't fit in the page and jumps out and exit form both left and right side. how i can set a limitation and avoid element from exiting ?
$(document).ready(function() {
$('#fastleft').click(function() {
$('#ball').toggleClass('rotated');
$('#ball').animate({
'marginLeft': "-=300px"
});
});
$('#moveleft').click(function() {
$('#ball').toggleClass('rotated');
$('#ball').animate({
'marginLeft': "-=20px"
});
});
$('#moveright').click(function() {
$('#ball').toggleClass('rotated');
$('#ball').animate({
'marginLeft': "+=20px"
});
});
$('#fastright').click(function() {
$('#ball').toggleClass('rotated');
$('#ball').animate({
'marginLeft': "+=300px"
});
});
});
#ball {
width: 50px;
height: 50px;
display: inline-block;
/*background-image: url(./boll.png);*/
background-color:red;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
position: relative;
}
.rotated {
animation-duration: 0.5s;
animation-name: ball;
}
#keyframes ball {
0% {
transform: rotate(100deg)
}
25% {
transform: rotate(200deg)
}
50% {
transform: rotate(300deg)
}
100% {
transform: rotate(360deg)
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div id="butts">
<button id="fastleft" type="button">FastLeft</button></button>
<button id="moveleft" type="button">Left</button>
<button id="moveright" type="button">Right</button>
<button id="fastright" type="button">FastRight</button>
</div>
<br>
<div id="ball"></div>
</div>
Here's a more optimized version of your code using function and data attribute. Examine it and let me know if you have any questions understanding it.
var ball = $('#ball');
var position = 0;
var bw = ball.width();
var ww = $('body').width();
$('button').click(function() {
var speed = $(this).data('speed');
moveBall(speed);
});
function moveBall(px){
position+= px;
position = Math.min(position,ww-bw);
position = Math.max(position,0);
console.log(position);
ball.toggleClass('rotated').animate({
'marginLeft': position+"px"
});
}
#ball {
width: 50px;
height: 50px;
display: inline-block;
/*background-image: url(./boll.png);*/
background-color:red;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
position: relative;
}
.rotated {
animation-duration: 0.5s;
animation-name: ball;
}
#keyframes ball {
0% {
transform: rotate(100deg)
}
25% {
transform: rotate(200deg)
}
50% {
transform: rotate(300deg)
}
100% {
transform: rotate(360deg)
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div id="butts">
<button data-speed="-300" id="fastleft" type="button">FastLeft</button>
<button data-speed="-20" id="moveleft" type="button">Left</button>
<button data-speed="20" id="moveright" type="button">Right</button>
<button data-speed="300" id="fastright" type="button">FastRight</button>
</div>
<br>
<div id="ball"></div>
</div>
Try using other CSS properties like float and align instead of giving such large values in pixel to margin or padding properties. This will almost always push your elements out of your page especially if you are working with small screen sizes . Also you should try using bootstrap. It will make your life much easier.

Display none at the end of animation

I'm trying to make element dissapear at the end of animation but it doesn't work, can someone explain how to make exit animation with element dissappearing at the end of it?:
var test = document.getElementById("test");
test.addEventListener("click", displayOpacity);
function displayOpacity(event){
event.target.style.animation = "changeOpacity 1s linear";
if(event.target.style.opacity === 0){
event.target.style.display = "none";
}
}
.container .test {
text-align: center;
padding: 100px;
color: #fff;
background-color: #00f;
max-width: 500px;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
#-webkit-keyframes changeOpacity {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes changeOpacity {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<body>
<div class="container">
<div class="test" id="test">Custom Text</div>
</div>
<script src="main.js"></script>
</body>
Since you have tagged jQuery, wouldn't be it easier to do it with .fadeOut()? The display attribute of the element is being set to none just after the animation has ended.
$('#test').click(function(){
$(this).fadeOut();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='test'>Text</div>
Your issue is because the animation-fill-mode is not being respected as you're overwriting it by setting the animation rule directly on the element itself.
To fix this change your JS code to add a class on the element, and put the animation rule in there, along with the required fill mode:
var test = document.getElementById("test");
test.addEventListener("click", displayOpacity);
function displayOpacity(event) {
this.classList.add('changeOpacity');
}
.container .test {
text-align: center;
padding: 100px;
color: #fff;
background-color: #00f;
max-width: 500px;
}
.changeOpacity {
animation: changeOpacity 1s linear forwards;
}
#-webkit-keyframes changeOpacity {
0% { opacity: 1; }
100% { opacity: 0; }
}
#-webkit-keyframes changeOpacity {
0% { opacity: 1; }
100% { opacity: 0; }
}
#keyframes changeOpacity {
0% { opacity: 1; }
100% { opacity: 0; }
}
<div class="container">
<div id="test" class="test">
Test
</div>
</div>
The animation time is 1 second
event.target.style.animation = "changeOpacity 1s linear";
so just make a timeout
setTimeout(function(){
event.target.style.display = "none";
},1000)

Make HTML element disappear with CSS animation

I want to know if there is a way to make an HTML element disappear with an animation of CSS. So when the element gets removed from the page by some script, an animation shall display before the element actually gets removed.
Is this possible in an easy way? Or do I need to set a timer to my script that starts the animation with a duration of X and removes the element after time X?
I would get fancy with keyframes
#keyframes myAnimation{
0%{
opacity: 1;
transform: rotateX(90deg);
}
50%{
opacity: 0.5;
transform: rotateX(0deg);
}
100%{
display: none;
opacity: 0;
transform: rotateX(90deg);
}
}
#myelement{
animation-name: myAnimation;
animation-duration: 2000ms;
animation-fill-mode: forwards;
}
If the script is actually removing the DOM element, I don't believe there's a way to fade it out. I think the timer is your only option.
I use jQuery to implement this.
//jQuery
$(document).ready(function() {
var target = $("#div");
$("#btn").click(function() {
removeElement(target);
});
});
function removeElement(target) {
target.animate({
opacity: "-=1"
}, 1000, function() {
target.remove();
});
}
div {
width: 100px;
height: 100px;
background-color: #000;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
</head>
<body>
<div id="div"></div>
<input type="button" value="fadeout" id="btn">
</body>
</html>
Use transitions like this:
function waithide()
{
var obj = document.getElementById("thisone");
obj.style.opacity = '0';
window.setTimeout(
function removethis()
{
obj.style.display='none';
}, 300);
}
div
{
height:100px;
width :100px;
background:red;
display:block;
opacity:1;
transition : all .3s;
-wekit-transition : all .3s;
-moz-transition : all .3s;
}
<div id="thisone" onclick="waithide()"></div>
I think you would have to do it in two steps. first the animate. Then, after animate is done, remove the elem. See the function below. Perhaps it could be put in a jquery plugin?
<style>
#test{
background: red;
height: 100px;
width: 400px;
transition: height 1s;
}
#test.hide {
height: 0;
}
</style>
<div id="test"> </div>
<button>Hide the Div</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.js"></script>
<script>
$('button').click(function(){
removeWithAnimate('#test');
});
function removeWithAnimate(id){
$(id).addClass('hide');
setTimeout( function(){
$(id).remove()
},1000);;
}
</script>
$('button').click(function() {
removeWithAnimate('#test');
});
function removeWithAnimate(id) {
$(id).addClass('hide');
setTimeout(function() {
$(id).remove()
}, 1000);;
}
#test {
background: red;
height: 100px;
width: 400px;
transition: height 1s;
}
#test.hide {
height: 0;
}
<div id="test"> </div>
<button>Hide the Div</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.js"></script>
transition: .5s;
invisible:
opacity: 0;
visible:
opacity: 1;
transition will make it appear and disappear smoothly.

Categories

Resources