| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
…ng them `onItemsChanged` adopted every new item with `_addView`, which throws "View already has a parent" when the item is still parented elsewhere. Nothing ever un-parents items: `disposeNativeView` leaves `items` untouched, so items keep pointing at a SegmentedBar even after it is destroyed. Binding one `SegmentedBarItem[]` to a SegmentedBar inside a ListView item template therefore crashed on the second cell, since every cell got a fresh bar bound to the same array. Items are now detached through `_removeView` before being adopted, so the item is properly unloaded and torn down and can be re-attached to the new parent's native visual tree.
`onItemsChanged` adopted every new item with `_addView`, which throws "View already has a parent" when the item is still parented elsewhere, and nothing ever un-parents items when a TabView is destroyed. Binding one `TabViewItem[]` array to more than one TabView therefore crashed. Items are now detached through `_removeView` before being adopted, so they are unloaded and torn down properly and can be re-attached to the new parent's native visual tree.
|
View your CI Pipeline Execution ↗ for commit 682aeba
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗ ☁️ Nx Cloud last updated this comment at 2026-08-17 18:54:45 UTC |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
PR Checklist
What is the current behavior?
SegmentedBarBase.onItemsChanged and TabViewBase.onItemsChanged adopt each new item by calling this._addView(item), which throws when the item already has a parent:
Nothing ever un-parents those items. parent is only cleared by _removeView, and neither widget touches its items when it is destroyed — SegmentedBar.disposeNativeView only clears the tab listener / selection handler. So once a SegmentedBar is torn down, its items keep pointing at the dead bar forever.
The practical consequence: a component that holds a SegmentedBarItem[] field and binds it to a SegmentedBar inside a ListView item template crashes. ListView creates a fresh SegmentedBar per cell, all bound to the same array, so the second cell throws.
Originally reported as NativeScript/nativescript-angular#900.
@nativescript/angular currently works around this in its renderer by reaching in and assigning item.parent = undefined on every array-valued binding. That bypasses _removeView entirely, so _tearDownUI / _parentChanged never run and _context stays set — which makes _setupUI hit its this._context === context early return, and the item is never added to the new parent's native visual tree. Fixing it here lets that workaround go away.
What is the new behavior?
onItemsChanged now detaches an item from its previous parent through the public API before adopting it:
Applied identically in segmented-bar-common.ts and tab-view-common.ts (the latter keeps its existing "TabViewItem must have a view" check ahead of the detach). Because the detach goes through _removeView, the item is unloaded and torn down properly, _context is cleared, and _addView on the new parent can add it to the native visual tree.
Re-binding a shared item array no longer throws, and the items end up parented to the widget they were last assigned to.
Known and accepted limitation
If the previous parent is still alive, this steals the item from it, and that parent's items array will still list the now-detached item. This is inherent: a View has exactly one parent, so sharing a single item array between two live hosts cannot work. The goal here is "don't crash, last binding wins", not multi-parent support.
Tests
Added to apps/automated/src/ui/segmented-bar/segmented-bar-tests.ts and apps/automated/src/ui/tab-view/tab-view-tests.ts:
All four new tests pass. The full apps/automated suite was run on an iOS 26 simulator against both main and this branch: 1800 → 1804 passing, with an identical set of 12 pre-existing SAFEAREALAYOUT *_tab_bar_flat inset failures on both, so this change introduces no regressions.