-1

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 class="frame a">A</div>
  <div class="frame b">B</div>
</div>
Table
  • 11
  • 7

2 Answers2

0

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 );
George
  • 36,413
  • 9
  • 66
  • 103
0

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.

Zaira
  • 42
  • 2
  • Zaira this is much better! will it work without arrow functions? – Table Sep 11 '22 at 20:17
  • yes, had to look up the syntax since I stopped using those. import { setTimeout as wait } from "timers/promises"; async function test() { await wait(2000); } test(); This doesn't show error so I think it would work there, i usually use a const or arrow though... You can drop that in from async i think – Zaira Sep 13 '22 at 07:24