Skip to content

fix(aria/tree): avoid errors when destroyed before initialization - #34059

Open
nagahara-naoki wants to merge 2 commits into
angular:mainfrom
nagahara-naoki:fix-aria-tree-destroy-before-init
Open

nagahara-naoki wants to merge 2 commits into
angular:mainfrom
nagahara-naoki:fix-aria-tree-destroy-before-init

Conversation

@nagahara-naoki

Copy link
Copy Markdown
Contributor

Summary

Fixes #34058.

TreeItem and TreeItemGroup read required signal inputs during destruction, even when they are destroyed before the first change detection and ngOnInit has not run. A synchronously destroyed TestBed fixture therefore throws NG0950 for parent or ownedBy, despite the inputs being bound in its template.

Retain the tree, parent group, and owning item used during registration. Destruction only unregisters those retained references, so uninitialized directives have nothing to clean up. This follows the registration/cleanup approach used for combobox in #33974 (related issue #33972).

Adds regression tests for a static flat tree and a static nested tree destroyed before their first change detection, plus controls that destroy both after initialization. This PR only changes tree; no accordion changes or public API changes are included.

Validation

  • Before the fix, the Chromium tree suite reports 144 passed, 2 failed: the new early-destruction tests throw NG0950 for parent and ownedBy. Both initialized controls pass.
  • After the fix, pnpm test src/aria/tree --no-watch passes: 146 specs, 0 failures.
  • pnpm bazelisk test //goldens:aria_api passes.
  • pnpm ng-dev format changed --check passes.
  • TSLint passes for the three changed TypeScript files.
  • git diff --check passes.

Tested with Node.js 22.23.4 and pnpm 12.16.1 on macOS arm64. The full Material/CDK/Aria test suites and Firefox were not run locally; validation covers the Chromium tree suite and Aria API golden check. Detailed reproduction code, setup, and actual errors are in #34058.

Remember the tree, parent group, and owning item used during registration so destruction does not read required inputs before ngOnInit has run. Add regression tests for early destruction and controls for initialized trees.

Fixes angular#34058
@ok7sai

ok7sai commented Nov 5, 2026

Copy link
Copy Markdown
Member

Thanks for the contribution! A cleaner way might be moving the required input reads from ngOnInit and ngOnDestroy to an effect with an onCleanup in the constructor. Like

  constructor() {
    effect(onCleanup => {
      const owner = this.ownedBy();
      untracked(() => {
        this._deferredContent.deferredContentAware.set(owner);
        owner._register(this);
      });
      onCleanup(() => owner._unregister(this));
    });
  }

so we don't need to create new pointers, and don't need to handle when those input values have changed.

@nagahara-naoki

Copy link
Copy Markdown
Contributor Author

Thanks for the suggestion! Using effect with onCleanup makes sense and keeps registration and cleanup together. I’ll update both PRs and verify the behavior with tests.

Keep registration and cleanup together using effects instead of retained references. Cover changing tree and group owner inputs and update the API golden for removed lifecycle hooks.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(aria/tree): NG0950 when tree items or groups are destroyed before first change detection

2 participants