Blacksun
Blacksun

Reputation: 359

setTimeout to JS function inside another one

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>

Upvotes: 1

Views: 223

Answers (3)

user6748331
user6748331

Reputation:

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) 

Upvotes: 0

hallleron
hallleron

Reputation: 1992

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>

Upvotes: 0

Rory McCrossan
Rory McCrossan

Reputation: 337560

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.

Upvotes: 1

Related Questions