Waiting for next event cycle/DOM state change from JS interop in MAUI Blazor #10498
-
I am creating a MAUI Blazor app alongside a Blazor WASM app and keeping as much code in a shared RCL as possible. I am having trouble getting an animation to run properly. Basically I am opening and closing a nav menu with a height transition: My starting CSS looks like this, as the menu starts in a closed state: #nav-menu {
display: none;
height: 0;
overflow: hidden;
transition: height .3s ease;
} When the menu button is clicked I call a JS interop method to set the display to const expandMenu = (div: HTMLDivElement): void => {
div.style.display = "block";
// Wait here so the DOM has time to render the new display value
window.requestAnimationFrame(() => {
let height: number = getTotalHeight(div); // Function that calculates height of div from its children
div.style.height = `${height}px`;
});
} I have an event listener for when the transition ends to then set the height to document.addEventListener("transitionend", (e: TransitionEvent) => {
if (e.propertyName === "height") {
let element:HTMLElement = <HTMLElement>e.target;
if (element.clientHeight === 0) element.style.removeProperty("display");
else element.style.height = "auto";
}
}); The problem comes from the method call to close the menu. I am doing a similar thing where I calculate the current height of the menu in order to start the animation from there, and then remove the height style so that it gets set back to 0 (defined in the CSS): const collapseMenu = (div: HTMLDivElement): void => {
let height: number = getTotalHeight(div);
div.style.height = `${height}px`;
// Wait here so DOM has time to render the static height value
// **Not Working**
window.requestAnimationFrame(() => {
div.style.removeProperty("height");
});
} The window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
div.style.removeProperty("height");
});
}); However, that feels ugly. I imagine it has something to do with event cycles different between the two application types or the time it takes for the DOM to be rerendered because it seems to be removing the height property before it gets a chance to set it so it basically just skips the animation. But like I said, it works fine in Blazor WASM without any weird tricks like calling Any insight would be appreciated. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Figured out why it is like that right after I posted this but can't seem to delete this post. Anyway, setting the height and removing the height were being applied at the same time because the callback of the |
Beta Was this translation helpful? Give feedback.
Figured out why it is like that right after I posted this but can't seem to delete this post. Anyway, setting the height and removing the height were being applied at the same time because the callback of the
requestAnimationFrame()
method is set to run before the next repaint. That's why I need to wait two frames, so it will set the height in the first and remove it in the second. I'm still guessing this is not an issue in the WASM app because of the difference in event cycles for each of them or innate features of running in a real browser. So anyway, I guess calling it twice is the correct solution.