Vuetify: [Bug Report] Tab height stuck for tab-item with lazy, transition and async content

Created on 10 Apr 2019  路  10Comments  路  Source: vuetifyjs/vuetify

Versions and Environment

Vuetify: 1.5.10
Last working version: 1.2.10
Vue: 2.6.10
Browsers: Chrome 71.0.3578.80
OS: Windows 10

Steps to reproduce

Create tab-item with combination of lazy and transition props, where tab's content is loaded asynchronously.

Expected Behavior

Tab height expands to fit content

Actual Behavior

Tab height remains fixed with an inline style, hiding async content

Reproduction Link

https://codesandbox.io/s/m45l18nw3y

Other comments

See codesandbox link... problem only occurs when all three conditions are met (lazy, transition, async content).

Workaround was to add style below, but not sure if this will create problems inside a v-dialog

.v-tabs .v-window__container {
  height: auto !important;
}
VWindow bug has workaround

Most helpful comment

My issue:
image

Issue consistently repeatable when rapidly switching between tabs; when second transition is called while first one is still going.

What i found was that properties of v-window component internalHeight and isActive don't get reset. I manually reset them, to null and false respectively, and issue disappears.

Now looking for a way to make all v-window components do this without copy-pasting to all the places i use v-window...

// window is v-window ref
// windowTimeout is component data variable
// @change event for v-tabs
    ensureWindow() {
      clearTimeout(this.windowTimeout);
      this.windowTimeout = setTimeout(() => {
        this.$refs.window.internalHeight = null;
        this.$refs.window.isActive = false;
      }, 1000);
    }

All 10 comments

This might be a bug in vue, onAfterEnter isn't called on the first two tabs for some reason.

Your custom-transition doesn't actually have any css, so vue can't know when it ends. If you just want to disable the transition you should use false: https://codesandbox.io/s/r0kxr6x3nn

Right, so in my application I'm using fade-transition and that's how I discovered the problem.

I created a new codesandbox (https://codesandbox.io/s/o403om35ky) and did some more testing.
Apparently the problem is not present for all of the built-in transitions only fade-transition and expand-transition.

Haven't yet tested a real custom-transition -- I'll try to see if that works or not.
And of course, without the transition, there's no problem.

this may be related to a problem i'm having, some transitions dont emit events. https://codepen.io/anon/pen/vMJBVw

My issue:
image

Issue consistently repeatable when rapidly switching between tabs; when second transition is called while first one is still going.

What i found was that properties of v-window component internalHeight and isActive don't get reset. I manually reset them, to null and false respectively, and issue disappears.

Now looking for a way to make all v-window components do this without copy-pasting to all the places i use v-window...

// window is v-window ref
// windowTimeout is component data variable
// @change event for v-tabs
    ensureWindow() {
      clearTimeout(this.windowTimeout);
      this.windowTimeout = setTimeout(() => {
        this.$refs.window.internalHeight = null;
        this.$refs.window.isActive = false;
      }, 1000);
    }

My issue:
image

Issue consistently repeatable when rapidly switching between tabs; when second transition is called while first one is still going.

What i found was that properties of v-window component internalHeight and isActive don't get reset. I manually reset them, to null and false respectively, and issue disappears.

Now looking for a way to make all v-window components do this without copy-pasting to all the places i use v-window...

// window is v-window ref
// windowTimeout is component data variable
// @change event for v-tabs
    ensureWindow() {
      clearTimeout(this.windowTimeout);
      this.windowTimeout = setTimeout(() => {
        this.$refs.window.internalHeight = null;
        this.$refs.window.isActive = false;
      }, 1000);
    }

Great! Thanks

not sure if this helps but I modified the CSS and it seems to fix this
https://developer.mozilla.org/en-US/docs/Web/CSS/unset

it appears that a style tag is being added to the active window div

.v-tabs .v-window__container {
height: unset!important;
}

image

I'm seeing this on Version 2.0. However my problem is the inverse. I have content loaded async calls. Version 2.0 seems to lazy load tabs by default, so after I have loaded my tabs (by clicking on them) and have switched between them I end up with a few tab-item components that have a height greater than their actual contents.

I have a deep suspicion that this issue could be tied to #7102 as it seems to be an issue caused during the transition between tabs, and #7102 is also an issue with the transition between tabs.

I'm giving this one a try. Please ignore https://github.com/SavantOne/vuetify/commit/ba16a6a1225949c23d03200bea2e8e1e723043c0, that was my testing change with bunch of logs. See https://github.com/SavantOne/vuetify/commit/02a7f6cc740366c5c7549f2f2a16207d79fd2fe3 instead.

Basically, the situation is a little bit more complicated than I though. I ran into this issue when I switch tabs really fast, and it happens from time to time. So looks like a racing condition to me. There are couple of race conditions in VWindowItem.ts. So the fix is simply putting bunch of checks to prevent re-entrant in each event handler, also putting a timer to ensure the container deactivates if anything goes wrong.

I'll need code review for committers to make sure I didn't do something wrong. And also tests for different platforms other than Windows/Chrome. Appreciate if anyone can give me a pointer to run test suties and/or anything I'm missing. Thanks!

FINDINGS

  • If transitionend fired before nextTick(), then done() is never
    going to be invoked.
  • onEnter() itself may be re-entered during transiton. Then the
    state is messed up.
  • onBeforeLeave() may be called after cancel, then the height
    is stuck.
  • onBeforeEnter() may be re-entered after first call. Calling
    this multiple times also wrongly reset transition state.

SOLUTION

  • Put correct guards on each event handler. Check of isActive and
    wasCancelled accordingly for each event to prevent re-entrant.
  • Put a timer in onEnter() to ensure done() is always invoked and
    deactivate() after timeout if anything goes wrong.

TESTS

  • Add log instrumentations for observation.
  • Test quickly switching tabs and see container always deactivate.
Was this page helpful?
0 / 5 - 0 ratings

Related issues

KuroThing picture KuroThing  路  3Comments

cawa-93 picture cawa-93  路  3Comments

efootstep picture efootstep  路  3Comments

itanka9 picture itanka9  路  3Comments

Antway picture Antway  路  3Comments