Yasar Abdullah
Yasar Abdullah

Reputation: 211

How to show loading icon till await finishes

I have a async function with await fetch. I want to show a loading icon to user till the await completes and then show the next div.

                let getOTP = await fetch(url, {
                    method: 'POST',
                    headers: {
                        "Content-Type": "text/plain"     
                    },
                    body: JSON.stringify({
                        "Number": mobileNumber
                    })
                });

                let data = await getOTP.json();
                let errorCode = data.errorCode;
                if (errorCode == 0) {// show next div}

I have tried used setTimeout(function (){},5000) functions set to 5 seconds (or more) but sometimes it takes longer for the reply to come. So, How do I show a loading icon till the await completes ?

Upvotes: 10

Views: 21246

Answers (3)

lankovova
lankovova

Reputation: 1426

Simply display loader before fetch, and remove it after await.

const fetchButton = document.querySelector('#fetchButton')
const loader = document.querySelector('#loader')
const content = document.querySelector('#content')

function fetchData() {
  // Here should be your api call, I`m using setTimeout here just for async example
  return new Promise(resolve => setTimeout(resolve, 2000, 'my content'))
}

fetchButton.onclick = async function () {
  content.innerHTML = ''

  // Your loader styling, mine is just text that I display and hide
  loader.style.display = 'block'
  const nextContent = await fetchData()
  loader.style.display = 'none'

  content.innerHTML = nextContent
}
<button id="fetchButton">Fetch</button>
<div id="loader" style="display: none">Loading...</div>
<div id="content"></div>

Upvotes: 11

Rohit.007
Rohit.007

Reputation: 3502

Start the loading image in the beginning of your code and stop it when there is no error and your code enter in the (errorCode == 0) condition.

            <-- START loading Here -->
            let getOTP = await fetch(url, {
                method: 'POST',
                headers: {
                    "Content-Type": "text/plain"     
                },
                body: JSON.stringify({
                    "Number": mobileNumber
                })
            });

            let data = await getOTP.json();
            let errorCode = data.errorCode;
            if (errorCode == 0) {
               <-- STOP loading Here -->
            }else{
               <-- STOP loading Here on error -->
            }

Upvotes: 0

NineBerry
NineBerry

Reputation: 28499

Just put the code to hide the icon after the line that calls await. Use try / finally to make sure that the code is also executed when something goes wrong in your asynchronous call.

You can encapsulate this mechanism in a function like the WithIcon function as shown below to reuse it at different places.

// Test function
async function test()
{
    await WithIcon(timeout(3000));
    testAfterAction();
}

function testAfterAction()
{
    var elem = document.createElement('div');
    elem.innerText = "Some text";
    document.body.appendChild(elem);	
}

// Use setTimeout to symulate some asynchronous i/o operation
function timeout(ms) 
{
    return new Promise(resolve => setTimeout(resolve, ms));
}


// While awaiting the promise, show a wait icon
async function WithIcon(promise)
{
    ShowAwaiting();
    try
    {
        await promise;
    }
    finally
    {
        HideAwaiting();
    }
}

// To only hide the icon when every ShowAwaiting call was met with a HideAwaiting call
var globalAwaitingCounter = 0;

// Show wait icon
function ShowAwaiting()
{
    if(globalAwaitingCounter <= 0)
    {
        document.getElementById("awaiting").style.display = "inline";
        globalAwaitingCounter = 1;
    }
    else
    {
        globalAwaitingCounter++;
    }
}

// Hide wait icon
function HideAwaiting()
{
    if(globalAwaitingCounter <= 1)
    {
        document.getElementById("awaiting").style.display = "none";
        globalAwaitingCounter = 0;
    }
    else
    {
        globalAwaitingCounter--;
    }
}
<html>
<body>
  <button type="button" onclick="test();">Test</button>
  <span id="awaiting" style="display:none">Awaiting....</span>
</body>
</html>

Upvotes: 0

Related Questions