Skip to content

fix(framework): await pending language change in connectedCallback instead of skipping first render#13798

Merged
ilhan007 merged 1 commit into
mainfrom
fix/language-aware-onEnterDOM
Jul 8, 2026
Merged

fix(framework): await pending language change in connectedCallback instead of skipping first render#13798
ilhan007 merged 1 commit into
mainfrom
fix/language-aware-onEnterDOM

Conversation

@ilhan007

@ilhan007 ilhan007 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #13602. That PR made connectedCallback bail out early for language-aware components mounted while a language change was in progress. The early-return path silently skipped onEnterDOM(), _fullyConnected = true, and the _domRefReadyPromise resolution — so consumers that register listeners or observers in onEnterDOM never saw those side effects wired up.

Reporter symptom

Reported against udex-footer (built on top of UI5 Web Components):

onEnterDOM(): void {
    if (isDesktop()) {
        this.setAttribute("desktop", "");
    }
    ResizeHandler.register(this, this._handleResizeBound);
}
  • App calls setLanguage("zh_CN") without awaiting → language change pending.
  • <udex-footer> inserted while pending → connectedCallback hits the early return at UI5Element.ts:362.
  • ResizeHandler.register never runs → mobile Accordion never appears because the resize observer never fires.

Fix

Instead of bailing out (which desynchronized the lifecycle), await the pending language change and then continue on the normal render path. To make that ergonomic, languageChangePending in Language.ts is repurposed from a boolean flag into a promise handle — the in-flight settlement promise, or null when no change is pending.

Language.ts

  • languageChangePending: Promise<void> | null replaces the boolean.
  • A single startLanguageChange helper builds the promise (chaining fireLanguageChange + the deferred reRenderAllUI5Elements) and clears the field on .finally — only if a newer change hasn't already replaced it.
  • Both setLanguage() and the cross-runtime attachConfigChange handler share the helper, so both paths keep the field consistent.
  • getLanguageChangePending() now returns the in-flight promise or null.

UI5Element.tsconnectedCallback

const languageChangePending = getLanguageChangePending();
if (ctor.getMetadata().isLanguageAware() && languageChangePending) {
    await languageChangePending;
}
// ...normal render path continues, onEnterDOM fires exactly as usual

A small guard skips the redundant renderImmediately(this) if the deferred reRenderAllUI5Elements already rendered the element during the await.

UI5Element.ts_invalidate
Unchanged. getLanguageChangePending() in a truthy context still means "a change is in flight, don't invalidate now".

Why this shape

  • Preserves the lifecycle invariant. onEnterDOM fires exactly once, after the first render, on the natural code path — no deferred bookkeeping.
  • Single source of truth. One field on Language.ts — either a promise or null — captures pending-ness. No boolean/promise pair to keep in sync.
  • Composable. Any future consumer that needs "wait for locale data to be ready" can await getLanguageChangePending() without adding another synchronization surface.

Tests

  • New test element packages/base/test/test-elements/LanguageAwareLifecycle.tsxlanguageAware: true, counts each lifecycle hook invocation.
  • New spec packages/base/cypress/specs/LanguageAwareLifecycle.cy.tsx:
    • onEnterDOM fires exactly once after a pending language change resolves
    • onEnterDOM does not fire a second time on a subsequent re-render
    • onEnterDOM does not fire if the element is removed before rendering

Verified locally:

Backport

Should be cherry-picked to the 2.23.x line since #13602 shipped there and Udex is affected.

Related

@ilhan007 ilhan007 temporarily deployed to netlify-preview July 8, 2026 11:11 — with GitHub Actions Inactive
@sap-ui5-webcomponents-release

Copy link
Copy Markdown

…st render

PR #13602 made connectedCallback bail out early for language-aware components
mounted while a language change was in progress. That path silently skipped
onEnterDOM, _fullyConnected, and _domRefReadyPromise resolution — so consumers
that register listeners or observers in onEnterDOM (e.g. the Udex Footer's
ResizeHandler.register call) never saw those side effects wired up.

Replace the boolean pending flag with a promise handle so connectedCallback can
await it directly and then continue on the normal render path. This keeps the
lifecycle invariant intact (onEnterDOM fires exactly once, after the first
render) and removes the need for any deferred-lifecycle bookkeeping.

Language.ts:
- languageChangePending changes from boolean to Promise<void> | null.
- A single startLanguageChange helper builds the promise, runs the deferred
  reRenderAllUI5Elements, and clears the field when done (only if a newer
  change hasn't replaced it).
- setLanguage() and the cross-runtime attachConfigChange handler share the
  helper, so both paths keep the field consistent.
- getLanguageChangePending() now returns the in-flight promise or null.

UI5Element.ts:
- connectedCallback awaits the pending promise for language-aware components,
  then proceeds normally. If the deferred re-render already rendered the
  element during the await, skip the redundant renderImmediately.
- _invalidate keeps its existing guard - a non-null promise is truthy, so the
  boolean check still works semantically.

Tests:
- New LanguageAwareLifecycle test element (languageAware: true, counts hook
  calls).
- New base/cypress/specs/LanguageAwareLifecycle.cy.tsx covering:
  * onEnterDOM fires exactly once after a pending language change resolves
  * onEnterDOM does not fire a second time on a subsequent re-render
  * onEnterDOM does not fire if the element is removed before rendering

Verified locally:
- 3/3 pass with the fix, 2/3 fail without it.
- Existing DatePicker_cldr_race and i18n_texts specs still pass.
@ilhan007 ilhan007 force-pushed the fix/language-aware-onEnterDOM branch from 841f417 to 163bf61 Compare July 8, 2026 11:52
@ilhan007 ilhan007 temporarily deployed to netlify-preview July 8, 2026 11:52 — with GitHub Actions Inactive
@ilhan007 ilhan007 changed the title fix(framework): fire onEnterDOM for language-aware components after deferred first render fix(framework): await pending language change in connectedCallback instead of skipping first render Jul 8, 2026
@ilhan007 ilhan007 requested a review from nnaydenow July 8, 2026 12:36
@ilhan007 ilhan007 merged commit 7086878 into main Jul 8, 2026
20 of 21 checks passed
@ilhan007 ilhan007 deleted the fix/language-aware-onEnterDOM branch July 8, 2026 13:08
@ilhan007 ilhan007 temporarily deployed to netlify-preview July 8, 2026 13:08 — with GitHub Actions Inactive
@sap-ui5-webcomponents-release

Copy link
Copy Markdown

🧹 Preview deployment cleaned up: https://pr-13798--ui5-webcomponents.netlify.app

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants