Fix TabView collapsing to zero height after model reset - #6295
Open
juliuspfadt wants to merge 1 commit into
Open
Fix TabView collapsing to zero height after model reset#6295juliuspfadt wants to merge 1 commit into
juliuspfadt wants to merge 1 commit into
Conversation
itemStack height was bound via rep.itemAt(currentIndex).height, installed only in onCurrentIndexChanged. itemAt() is not notifiable: after a model reset (values/source change -> beginResetModel) delegates are destroyed and recreated, but if currentIndex stays the same the binding keeps referencing the destroyed wrapper -> height 0 -> TabView folds up and stays folded. Frequent with nested TabViews driven by dynamic values (e.g. MNLFA in jaspSem). Replace with push-based tracking: each wrapper pushes its height when it is the current StackLayout item (isCurrentItem attached prop), so freshly created delegates always announce their height. Also fixes initial height when currentIndex never changes from 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes an intermittent UI layout failure where TabView content could collapse to zero height after the underlying tab model resets (common with dynamic/nested TabViews whose model is recomputed). The solution replaces a fragile pull-based height binding (dependent on Repeater.itemAt()) with push-based height tracking from the currently active delegate.
Changes:
- Replace
onCurrentIndexChanged-installed height binding with a persistent declarativeheightbinding on theStackLayout. - Introduce
currentTabHeighton theStackLayout, updated by delegates when they become current and when their height changes. - Add inline documentation explaining why
Repeater.itemAt()cannot be safely used as a binding dependency across model resets.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
TabViews with dynamic
values/sourceintermittently collapse to zero height (tab bar visible, content folded to nothing) and stay collapsed. Most visible in jaspSem's Moderated Nonlinear Factor Analysis, which nests TabViews 3 levels deep withvalues:recomputed from checkbox states and factor lists.Root cause
itemStack(the StackLayout holding tab content) got its height via:Two defects:
currentIndexchanges. If it never does (single tab, or index staying at 0), no height binding exists at all.Repeater.itemAt()is a plain function — not notifiable. Anyvalues/sourcechange triggers a full model reset (ListModel::_initTerms→beginResetModel()), destroying and recreating all delegates. IfcurrentIndexstays the same, the binding's only tracked dependencies arecurrentIndexand the destroyed wrapper'sheight— it never re-evaluates, keeps referencing the dead item, and the TabView collapses to 0. The collapse latches: StackLayout writes height 0 onto the current item, and since row controls are cached C++-side, nothing re-triggers the binding.With nested TabViews, a collapse at any level zeroes the level above → the whole stack folds.
Fix
Push-based height tracking: each delegate pushes its height into
itemStack.currentTabHeightwhenever it is the current item (StackLayout.isCurrentItemattached property, plusComponent.onCompletedfor creation ordering). Freshly created delegates after a model reset always announce their height, so no stale references are possible.heightonitemStackis now a plain declarative binding with guards for empty model / index −1.No public API change (
content,currentIndexalias, add/remove tabs untouched). SEM/PLSSEMcontent:-style usage unaffected — their initial-height case (defect 1) is fixed too.Test checklist (jaspSem MNLFA, dataset with ≥6 scale variables)
TypeError: Cannot read property 'height' of null, no binding-loop warnings.🤖 Generated with Claude Code