3

I am working on a part of page, where I have 4 main divs, one of the divs has its height calculated depending on the heights of the other divs, and one of these other divs can disappear.

<div header></div>
<div divWithCalculatedHeight></div>
<div checkout></div>
<div disappearingDiv></div>

The way I am calculating the height of the 2nd div is pretty simple totalHeight - $header.outerHeight() - $checkout.outerHeight() - $disappearingDiv.outerHeight() and while all divs are visible this is working just fine. However I have buttons with events attached to them, that can make the 4th div disappear and appear back again. And this is my issue:

$buttonHide.trigger("hideFourthDiv")

$disappearingDiv.on("hideFourthDiv", () => { 
    $disappearingDiv.css({ display: "none" }); 
    calculateNew2ndDivHeightAndSetIt();
});

And this works just fine, but the reappearing:

$buttonShow.trigger("showFourthDiv")

$disappearingDiv.on("showFourthDiv", () => { 
    $disappearingDiv.css({ display: "block" }); // i have also tried with "initial"

    console.log($disappearingDiv.outerHeight()); // this here gives 0, so height of 2nd div cant be calculated properly

    calculateNew2ndDivHeightAndSetIt();
});

This here is my issue, when I make the div re-appear, while still inside the event, the outerHeight() returns 0, I have also tried with height() it too returns 0. Now it is important to note here that, if I click the button twice, on the second click it will work, which in a way coincides with my further thoughts:

Now, if click the buttonShow to trigger the showign event (just once!), and then I go into my browser console and manually type $disappearingDiv.outerHeight(), it does give me the correct height and not a 0!

So I thought that maybe, since I am still within the event, at that point in time, the DOM maybe is not yet updated, and jQuery doesnt see the "shown" element, so with that in mind I searched for a way to trigger my function outside of the event, once the div is shown and I found out about MutationObserver

So I tried implementing it:

const target = $disappearingDiv;
const config = { childList: true, subtree: true};
const callback = () => {console.log($disappearingDiv.height())};
const observer = new MutationObserver(callback);

observer.observe(target, config);

That code is not placed within any of the 2 events, it is inside the "DOMContentLoaded" event.

It does get triggered, when I hide/show, but it still gives me a 0 the first time I click the button.

So my question I am guessing is, how to manage to get the height of the disappearingDiv once it has reappered, from the first call of the events, so that I dont have to click the button two times.

Edit: I figured out what is the issue, but I can't find solution, when css is applied, it applies it inline, but the browser is not repainting immediatelly or whatever, that is why when I immediatelly check for height it is not yet available. I need to wait for the css of the element to be updated and then get the height. If I place the updating function within a timeout it will work with a timeout of as low as 1 ms. I have opened a new question after these new findings: Wait for css of element to be updated when it is dynamically changed with JS/Jquery

Darkbound
  • 3,026
  • 7
  • 34
  • 72
  • are there any animations while showing the div? – cagri Dec 25 '20 at 11:07
  • @cagri nope, hiding is with display: none; and showign is with display: block; thats all – Darkbound Dec 25 '20 at 11:32
  • @cagri you may be on to something, because I tried with a timeout of 500 seconds now, and now I do get the height, so maybe there is something somewhere inherited. – Darkbound Dec 25 '20 at 11:39
  • 1
    I meant to say 500 miliseconds in my previous post, but I got it to work with a timeout of as low as 1 ms. Still that is not safe, and I can't figure out what is preventing the outerHeight from getting the height right after display is set to block. – Darkbound Dec 25 '20 at 11:54
  • 1
    I figured out what is the issue, but I can't find solution, when css is applied, it applies it inline, but the browser is not repainting immediatelly or whatever, that is why when I immediatelly check for height it is not yet available. I need to wait for the css of the element to be updated and then get the height. – Darkbound Dec 25 '20 at 12:08
  • Are you able to create a demo of your issue? That would help out in debugging. – Emiel Zuurbier Dec 25 '20 at 13:27
  • Try using `hide()` and `show()` functions instead of `css()` – firatozcevahir Dec 25 '20 at 14:04
  • @firatozcevahir hide() and show() do the same thing, they set display to none and to block. – Darkbound Dec 25 '20 at 17:03
  • 1
    Yes but you can pass a function as a second parameter in `hide()` or `show()` functions to get the height after hiding or showing finished. – firatozcevahir Dec 26 '20 at 22:50
  • @firatozcevahir yes .show({ done: (res) => { res.then(() => { console.log($element.outerHeight()); }); }, }); that did work, but I also found out that I can do setTimeout with 0 or just setTimeout(func) with no arguments and that simply schedules the function to run on the next event loop looping and that works too and seems a bit cleaner, but I'll see which one I'll end up using. You can add it as an answer and I will accept it since it works. – Darkbound Dec 27 '20 at 18:53

1 Answers1

1

You could use requestAnimationFrame() to wait for a render to happen before checking the height of the div. This would be doing something like using setTimeout but with waiting for the next render instead of waiting or n amount of milliseconds.

$disappearingDiv.on("showFourthDiv", () => { 
  $disappearingDiv.css({ display: "block" }); // i have also tried with "initial"
  
  requestAnimationFrame(() => {
    console.log($disappearingDiv.outerHeight()); // this here gives 0, so height of 2nd div cant be calculated properly.
    calculateNew2ndDivHeightAndSetIt();
  });
});
Emiel Zuurbier
  • 19,095
  • 3
  • 17
  • 32
  • Thanks for the suggestion, but it doesnt work (at least in my case, for some reason), however setTimeout with 0ms works. – Darkbound Dec 25 '20 at 13:04