Home > Software design >  how to delay an insertBefore?
how to delay an insertBefore?

Time:09-12

It is possible to stop an insertBefore, inside an addEventListener, to add a smooth css, so that the movement produced by the insertion of the div is not abrupt for the user?

I have read many questions, i have tried using settimeout in various ways, without success:

const gallery = document.getElementById('gallery');

const frames = gallery.querySelectorAll('.frame');

for (var i = 0; i < frames.length;   i) {

  frames[i].addEventListener('click', function() {

    if (this.className == "frame b") {

      //setTimeout( function(){

      gallery.insertBefore(this, this.previousElementSibling);

      //}, 1000 );

    } else {

      //setTimeout( function(){

      gallery.insertBefore(this, this.previousElementSibling);

      //}, 1000 );

    };

  });

};
.frame {
  width: 200px;
  height: 100px;
  font: bold 400% sans-serif;
  color: white;
  float: left;
}

.frame.a {
  background-color: brown;
}

.frame.b {
  background-color: purple;
}
<div id="gallery">
  <div >A</div>
  <div >B</div>
</div>

CodePudding user response:

this refers to a different context inside your setTimeout callback; it doesn't refer to the element for which the event is dispatched anymore.

There are a few ways you could do this, here are 3:

Use an arrow function, where this doesn't get bound to a new context:

setTimeout( () => {
    gallery.insertBefore(this , this.previousElementSibling);
}, 1000 );

Store a reference to this for use inside the callback:

const _self = this;

setTimeout( function(){
    gallery.insertBefore(_self , _self.previousElementSibling);
}, 1000 );

Manually bind the current context to the callback function:

setTimeout( function(){
    gallery.insertBefore(this, this.previousElementSibling);
}.bind(this), 1000 );

CodePudding user response:

Another angle I prefer for this is use this wait fn, tidy & concise.
wait fn src

// at the top of the file, or 1000 here and leave out 1000 in the call
const wait = (delay = 300) => new Promise((resolve) => setTimeout(resolve, delay));

// inside
frames[i].addEventListener('click', async () => {
    await wait(1000)
    if (this.className == "frame b") {
      gallery.insertBefore(this, this.previousElementSibling);
    } else {
      gallery.insertBefore(this, this.previousElementSibling);
    };
  });

Only trouble is sometimes forgetting the await keyword, hopefully you have an IDE that tells You when you don't need it, like prettier... Won't tell You when you've forgotten though since there are other valid ways to use it. Outer for loop is separate of this question since it's just assigning refs for later.
There is also now
import {setTimeout} from "timers/promises";
await setTimeout(1000);
From Node 16, you don't need the wait fn.

  • Related