Wait for css of element to be updated when it is dynamically changed with JS/Jquery

Viewed 287

So after a lot of searching about an issue that I am having, I figured out that the issue that I am having is, because when I apply css to the element, the info is not immediatelly available, here is what I mean:

I have an element that I am hiding and showing with display: block; and display: none;, the issue is that right after I show the element, I need to obtain its height:

$element.css({ display: "block"});

console.log($element.outerHeight()); // <- this returns 0

So I started experimenting with timeouts at some point, and even with a 1ms timeout, it still works and returns the correct height:

setTimeout(() => {
    console.log($element.outerHeight()); // with 1ms timeout, it works and gives real height
}, 1)

After figuring that out, with 1 ms delay it could not be some inherited transition or anything, so that got me thinking that maybe, between the jump from display: block; to .outerHeight() something is not yet updated, after some digging I found this:

Quote: "You'll see different behaviors in different browsers since jQuery is updating the markup with inline styles and the browser decides when to repaint."

Does jQuery's css method block until the change is fully applied?

And this seems to be my actual problem, so the question now is, how do I figure out when that repainting has happened, I have tried with onload, load events but none of them get triggered.

I have also tried the suggested code in that post with animation:

$element.animate({
  display: 'block'
}, {
  duration: 0,
  done: function(animation, jumpedToEnd) {
    console.log($element.outerHeight());
  }
})

But that did not work either.

1 Answers

The issue you are having is that you do not really have control on how the browser is displaying changes. The information is not immediately available, as you have pointed out and even though doing timeouts is technically a solution, it lacks elegance and endangers your UI of getting into callback hell.

What you will need to test in order to see whether more elegant solutions work is

1. Whether it works with 0 milliseconds

If it works with 0 milliseconds, then basically the UI is refreshed just after the function is successfully executed and before the next function from the event loop is running.

2. Whether doing it without jQuery behaves differently

Compare the behavior of

$element.css({ display: "block"});

with

for (let index = 0; index < $element.length; index++) {
    $element[index].style.display = "block";
}

is equivalent. If so, then it's not a jQuery problem. If not, then it's a jQuery problem.

Conclusion

As a general guidance, you will probably need a callback-like behavior and to achieve that you will probably want to use the promise architecture. If it works.

Related