-
Notifications
You must be signed in to change notification settings - Fork 69
airframe-rx-html: onMount may not be able to find the rendered DOM element #3453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Labels
Comments
6 tasks
xerial
added a commit
that referenced
this issue
Jun 2, 2025
## Problem When RxElements with ID attributes are rendered in nested sequences, the `onMount` callback may be called before the DOM element is actually available via `document.getElementById()`. This causes issues when `onMount` code tries to find elements by their ID. Example that demonstrates the issue: ```scala class HoverableTextLabel(txt: RxElement, hoverMessage: String) extends RxElement: private val elementId = ULID.newULIDString override def onMount: Unit = RxDOM.getHTMLElementById(elementId).foreach { el => // This may fail because element is not yet available by ID try Dynamic.newInstance(Dynamic.global.bootstrap.Tooltip)(el) catch case e: Throwable => warn(e) } override def render: RxElement = span( id -> elementId, data("bs-toggle") -> "tooltip", txt ) div( Seq[RxElement]( HoverableTextLabel("hello", "mouseover message") ) ) ``` ## Root Cause The previous implementation used a `MutationObserver` to detect when elements were added to the DOM and then immediately called `onMount`. However, there was a timing race condition where the element was added to the DOM but not immediately available via `document.getElementById()` due to browser batching of DOM updates. ## Solution Modified `DOMRenderer` to ensure elements with IDs are fully available before calling `onMount`: 1. **Mount element to DOM first** - The element is added to the DOM tree 2. **Check for ID attribute** - Determine if the element has an ID that needs to be queryable 3. **Verify availability** - For elements with IDs, verify they're available via `document.getElementById()` 4. **Retry if needed** - Use `setTimeout` with 0ms delay to retry if element not immediately available 5. **Preserve existing behavior** - For elements without IDs, call `onMount` immediately as before ## Testing Added a comprehensive test case that reproduces the original issue and verifies the fix works: ```scala test("onMount should find element by ID in nested sequences") { class HoverableTextLabel(txt: RxElement, hoverMessage: String) extends RxElement { private val elementId = s"element-${System.nanoTime()}" override def onMount(n: Any): Unit = { RxDOM.getHTMLElementById(elementId) match { case Some(el) => foundElement := true // Should succeed case None => // Should not happen with fix } } // ... render implementation } // Test passes with fix, was failing before } ``` All existing `onMount` tests continue to pass, ensuring backward compatibility. Fixes #3453. --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: xerial <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If an RxElement is rendered in a nested sequence, onMount can be called a bit earlier than rendered element actually appears in the browser.
An example:
The text was updated successfully, but these errors were encountered: