1

I have problem with temporary modifying div CSS for creating loading screen while something is computing or modifying area under shadow div.

Expected result:

  1. Click button.
  2. Div is masked with a shadow (for loading animation).
  3. Code is doing something time hungry.
  4. After 2 is done, shadow is removed.

Current result

  1. Click button.
  2. Code is doing something time hungry.
  3. Div is masked with a shadow (Tested with commented PART 3).
  4. Then is instantly removed, without being visible.

Tried:

This code with and without promise.

Code snipped:

$('#butt').on('click', function() {
     console.log('test1');
     document.getElementById('info').innerHTML = '';
     new Promise((resolve, reject) => {
     //PART 1 ------------------------------------------------------
          let height = document.getElementById('el1').getBoundingClientRect().height
                  + document.getElementById('el2').getBoundingClientRect().height
                  + document.getElementById('el3').getBoundingClientRect().height;
          document.getElementById('info').innerHTML += height+'<br>';
          document.getElementById('shadow').style.height = ''+height+'px';
          document.getElementById('info').innerHTML += document.getElementById('shadow').style.height+'<br>';
          document.getElementById('shadow').style.top = ''+(-height)+'px';
          document.getElementById('shadow').classList.add("w3-show");
          document.getElementById('butt').classList.add("w3-disabled");
          resolve();
     }).then(() => {
     //PART 2 ------------------------------------------------------
          //Do anything that not finish instantly.
          let a = 0;
          let i = 10000;
          while(i!=0) {
            i--;
            document.getElementById('info').innerHTML += a;
            a = a + Math.log(a);
          };
          console.log('test2');
     }).then(() => {
     //PART 3 ------------------------------------------------------
          console.log('test3');
          document.getElementById('shadow').classList.remove("w3-show");
          document.getElementById('butt').classList.remove("w3-disabled");
     });
});
<!DOCTYPE html>
<html>
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <body>
    <button id='butt'>Show modal</button>
    <br>
    <p id='info'></p>
    <br>
    <div>
      <div id='el1' style="background-color: blue; heigh:10px; width:100px;">s</div>
      <div id='el2' style="background-color: green; heigh:10px; width:100px;">s</div>
      <div id='el3' style="background-color: red; heigh:10px; width:100px;">s</div>
      <div id='shadow' class='w3-hide' style="position: relative; background-color: black; heigh:5px; z-index: 2; opacity: 0.5; width:100px;">s</div>
      <br><br><br><br><br><br><br>
    </div>
  </body>
</html>
Maturutuki
  • 75
  • 8
  • The simplest way to temporarily apply CSS to a div is to add a class to it (that the temporary CSS targets) and then when you're done, remove that class. – jfriend00 Jan 31 '22 at 00:28
  • Eak! jQuery code and css code in HTML ! – Mister Jojo Jan 31 '22 at 00:48
  • Why do you want to use Promise in your case? I don't see a reason from it. – ikhvjs Jan 31 '22 at 07:48
  • @jfriend00 In my final code let 'height = ...' is changeable, and I'm doing it for hide and disable css class here. – Maturutuki Jan 31 '22 at 08:37
  • @Mister Jojo jQuery is from old code, atm im not adding more, css in html is just for prototype code here, not for the final code. – Maturutuki Jan 31 '22 at 08:45
  • @ikhvjs It was experimental try, because without promise it still do not work as intended (All css changes are applied after all calculations instead of showing shadow then calculate then removing shadow). – Maturutuki Jan 31 '22 at 08:45
  • @Maturutuki, I got you what you mean. I leave my answer to explain it. – ikhvjs Jan 31 '22 at 09:27
  • Hint: That while loop is better described as "processor-hungry" rather than "time-hungry". – Roamer-1888 Feb 01 '22 at 02:55

2 Answers2

1

This is actually a tricky question. Your first approach with synchrous code like below doesn't apply the css before the computation because DOM manipulation is synchronous, however, the browser's re-rendering of the page in response to a DOM update is asynchronous. That's why you don't see any updates of CSS because all the DOM manipulation applied immediately after all the synchronous is executed.

Example in synchronous below:

$("#butt").on("click", function () {
    //PART 1 ------------------------------------------------------
    let height =
        document.getElementById("el1").getBoundingClientRect().height +
        document.getElementById("el2").getBoundingClientRect().height +
        document.getElementById("el3").getBoundingClientRect().height;
    document.getElementById("info").innerHTML += height + "<br>";
    document.getElementById("shadow").style.height = "" + height + "px";
    document.getElementById("info").innerHTML +=
        document.getElementById("shadow").style.height + "<br>";
    document.getElementById("shadow").style.top = "" + -height + "px";
    document.getElementById("shadow").classList.add("w3-show");
    document.getElementById("butt").classList.add("w3-disabled");
    console.log("test1");
    //PART 2 ------------------------------------------------------
    //Do anything that not finish instantly.
    let a = 0;
    let i = 10000;
    while (i != 0) {
        i--;
        a = Number(document.getElementById("info").innerHTML);
        a = a + Math.log(a);
        document.getElementById("info").innerHTML = a;
    }
    console.log("test2");
    //PART 3 ------------------------------------------------------
    console.log("test3");
    document.getElementById("shadow").classList.remove("w3-show");
    document.getElementById("butt").classList.remove("w3-disabled");
});
<!DOCTYPE html>
<html>
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <body>
    <button id='butt'>Show modal</button>
    <br>
    <p id='info'></p>
    <br>
    <div>
      <div id='el1' style="background-color: blue; heigh:10px; width:100px;">s</div>
      <div id='el2' style="background-color: green; heigh:10px; width:100px;">s</div>
      <div id='el3' style="background-color: red; heigh:10px; width:100px;">s</div>
      <div id='shadow' class='w3-hide' style="position: relative; background-color: black; heigh:5px; z-index: 2; opacity: 0.5; width:100px;">s</div>
      <br><br><br><br><br><br><br>
    </div>
  </body>
</html>

What you can do is to use async/await approach to wait for all the DOM manipulation is finished before.

Example below:

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

$("#butt").on("click", async function () {
    //PART 1 ------------------------------------------------------
    let height =
        document.getElementById("el1").getBoundingClientRect().height +
        document.getElementById("el2").getBoundingClientRect().height +
        document.getElementById("el3").getBoundingClientRect().height;
    document.getElementById("info").innerHTML += height + "<br>";
    document.getElementById("shadow").style.height = "" + height + "px";
    document.getElementById("info").innerHTML +=
        document.getElementById("shadow").style.height + "<br>";
    document.getElementById("shadow").style.top = "" + -height + "px";
    document.getElementById("shadow").classList.add("w3-show");
    document.getElementById("butt").classList.add("w3-disabled");
    console.log("test1");
    //PART 2 ------------------------------------------------------
    //Do anything that not finish instantly.

    await delay(100);

    let a = 0;
    let i = 10000;
    while (i != 0) {
        i--;
        a = Number(document.getElementById("info").innerHTML);
        a = a + Math.log(a);
        document.getElementById("info").innerHTML = a;
    }
    console.log("test2");
    //PART 3 ------------------------------------------------------
    console.log("test3");
    document.getElementById("shadow").classList.remove("w3-show");
    document.getElementById("butt").classList.remove("w3-disabled");
});
<!DOCTYPE html>
<html>
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <body>
    <button id='butt'>Show modal</button>
    <br>
    <p id='info'></p>
    <br>
    <div>
      <div id='el1' style="background-color: blue; heigh:10px; width:100px;">s</div>
      <div id='el2' style="background-color: green; heigh:10px; width:100px;">s</div>
      <div id='el3' style="background-color: red; heigh:10px; width:100px;">s</div>
      <div id='shadow' class='w3-hide' style="position: relative; background-color: black; heigh:5px; z-index: 2; opacity: 0.5; width:100px;">s</div>
      <br><br><br><br><br><br><br>
    </div>
  </body>
</html>
ikhvjs
  • 5,316
  • 2
  • 13
  • 36
  • So an approach: Wait exactly amount of time needed to asynchronously re-render DOM is impossible and your suggestion is to guess that time, betting 100ms? – Maturutuki Jan 31 '22 at 12:46
  • @Maturutuki, You may have a look of this question https://stackoverflow.com/questions/3219758/detect-changes-in-the-dom – ikhvjs Jan 31 '22 at 13:03
  • I tried something from this, but still same effect, DOM is rendered after everything is done. Looks like i need to stay with delay, thanks. – Maturutuki Jan 31 '22 at 17:26
  • @Maturutuki, good that it helps. Anyway, would you accept this answer if it helps? – ikhvjs Feb 01 '22 at 10:11
0

Your part 2 is not returning any promise so .then() will have no effect using on that block 3. You can return a new promise as such:

$('#butt').on('click', function() {
     console.log('test1');
     document.getElementById('info').innerHTML = '';
     new Promise((resolve, reject) => {
     //PART 1 ------------------------------------------------------
          let height = document.getElementById('el1').getBoundingClientRect().height
                  + document.getElementById('el2').getBoundingClientRect().height
                  + document.getElementById('el3').getBoundingClientRect().height;
          document.getElementById('info').innerHTML += height+'<br>';
          document.getElementById('shadow').style.height = ''+height+'px';
          document.getElementById('info').innerHTML += document.getElementById('shadow').style.height+'<br>';
          document.getElementById('shadow').style.top = ''+(-height)+'px';
          document.getElementById('shadow').classList.add("w3-show");
          document.getElementById('butt').classList.add("w3-disabled");
          resolve();
     }).then(() => {
     //PART 2 ------------------------------------------------------
          //Do anything that not finish instantly.
         return new Promise((resolve,reject)=>{
          let a = 0;
          let i = 10000;
          while(i!=0) {
            i--;
            document.getElementById('info').innerHTML += a;
            a = a + Math.log(a);
          };
          console.log('test2');
          resolve()
          })

     }).then(() => {
     //PART 3 ------------------------------------------------------
          console.log('test3');
          document.getElementById('shadow').classList.remove("w3-show");
          document.getElementById('butt').classList.remove("w3-disabled");
     });
});
JaivBhup
  • 792
  • 4
  • 7