I have a use-case for keep-alive where the condition on which I have to keep the component alive is based on user input.
As of now, keep-alive supports include and exclude props that check component name.
There is no way I can keep-alive components based on conditions at runtime?
I鈥檓 looking for something like following:
<keep-alive :if="myCondition">
<component :is="myComponent"></component>
</keep-alive>
Here myCondition could be anything, be it computed or Vuex state or expression..
Using a v-if should work fine.
That being said, in most cases, trying to control keep-alive behaviour very precisely is harder than creating the necessary methods to restore the state you need
@posva
Actually I should've written it earlier, my use case has a big template inside keep-alive because I'm using named slots.
Now if I use v-if, that would mean that I have to maintain two templates that are exactly same except the keep alive wrapper.
Hence, I'm looking for a boolean to turn keep-alive's functionality on/off.
Something like following would be much better
<keep-alive :if="myCondition">
<component :ref="dialogOptions.compId" :is="dialogOptions.component" v-bind="dialogOptions.props">
<div slot="header" slot-scope="headerProps">
<v-toolbar dark color="primary">
<v-toolbar-title class="white--text">{{ headerProps.title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-tooltip v-show="headerProps.fullscreenButton" :close-delay="0" bottom>
<v-btn slot="activator" @click="dialogOptions.fullscreen = !dialogOptions.fullscreen" icon>
<v-icon v-show="dialogOptions.fullscreen">fullscreen_exit</v-icon>
<v-icon v-show="!dialogOptions.fullscreen">fullscreen</v-icon>
</v-btn>
<span>{{ dialogOptions.fullscreen?'Fullscreen off':'Fullscreen on' }}</span>
</v-tooltip>
<v-tooltip :close-delay="0" bottom>
<v-btn slot="activator" @click="dialogOptions.dialogRef.close()" icon>
<v-icon>close</v-icon>
</v-btn>
<span>Close</span>
</v-tooltip>
</v-toolbar>
</div>
</component>
</keep-alive>
than
<keep-alive v-if="myCondition">
<component :ref="dialogOptions.compId" :is="dialogOptions.component" v-bind="dialogOptions.props">
<div slot="header" slot-scope="headerProps">
<v-toolbar dark color="primary">
<v-toolbar-title class="white--text">{{ headerProps.title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-tooltip v-show="headerProps.fullscreenButton" :close-delay="0" bottom>
<v-btn slot="activator" @click="dialogOptions.fullscreen = !dialogOptions.fullscreen" icon>
<v-icon v-show="dialogOptions.fullscreen">fullscreen_exit</v-icon>
<v-icon v-show="!dialogOptions.fullscreen">fullscreen</v-icon>
</v-btn>
<span>{{ dialogOptions.fullscreen?'Fullscreen off':'Fullscreen on' }}</span>
</v-tooltip>
<v-tooltip :close-delay="0" bottom>
<v-btn slot="activator" @click="dialogOptions.dialogRef.close()" icon>
<v-icon>close</v-icon>
</v-btn>
<span>Close</span>
</v-tooltip>
</v-toolbar>
</div>
</component>
</keep-alive>
<component v-else :ref="dialogOptions.compId" :is="dialogOptions.component" v-bind="dialogOptions.props">
<div slot="header" slot-scope="headerProps">
<v-toolbar dark color="primary">
<v-toolbar-title class="white--text">{{ headerProps.title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-tooltip v-show="headerProps.fullscreenButton" :close-delay="0" bottom>
<v-btn slot="activator" @click="dialogOptions.fullscreen = !dialogOptions.fullscreen" icon>
<v-icon v-show="dialogOptions.fullscreen">fullscreen_exit</v-icon>
<v-icon v-show="!dialogOptions.fullscreen">fullscreen</v-icon>
</v-btn>
<span>{{ dialogOptions.fullscreen?'Fullscreen off':'Fullscreen on' }}</span>
</v-tooltip>
<v-tooltip :close-delay="0" bottom>
<v-btn slot="activator" @click="dialogOptions.dialogRef.close()" icon>
<v-icon>close</v-icon>
</v-btn>
<span>Close</span>
</v-tooltip>
</v-toolbar>
</div>
</component>
I see your concern... It's one of the cases wher JSX is easier than templates because you don't need to write that chunk of code twice
Since you're using the exact same component, have you thought of using activated and deactivated hooks?.
Related https://github.com/vuejs/vue/issues/6259
I'm not sure how easy/tough would it be to add JSX to my typescript vue-class-components or how easy would it be for me to translate this code to JSX..
And about the activated and deactivated event, are you hinting that I should manually destroy the component in deactivated if myCondition is true?
I think that would be a code smell for my case actually, because this code is an interface for our developers to open up a component in a dialog with some extra options.
So, they'd just do like following:
import Tiles from "../components/tiles.vue";
import Ceiling from "../components/ceiling.vue";
import sDialog from "@/services/sDialog";
//...other imports
@Component
export default class Settings extends Vue {
someOpenDialogMethod() {
sDialog.open({
component: Tiles,
keepAlive: true,
//... other options like
});
}
anotherOpenDialogMethod() {
sDialog.open({
component: Ceiling ,
keepAlive: false, //or may be this boolean is dynamic
//... other options like
});
}
}
A small generic functional component can easily achieve a conditional wrapper element:
// conditional-wrapper.js
export default {
functional: true,
props: {
tag: {
type: String,
default: 'DIV'
},
show: Boolean,
},
render(h, ctx) {
return this.show
? h(ctx.props.tag, ctx.data, ctx.children)
: this.slots().default[0]
}
}
<conditional-wrapper :tag="keep-alive" :show="myCondition">
<component :ref="dialogOptions.compId" :is="dialogOptions.component" v-bind="dialogOptions.props">
<div slot="header" slot-scope="headerProps">
<v-toolbar dark color="primary">
<v-toolbar-title class="white--text">{{ headerProps.title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-tooltip v-show="headerProps.fullscreenButton" :close-delay="0" bottom>
<v-btn slot="activator" @click="dialogOptions.fullscreen = !dialogOptions.fullscreen" icon>
<v-icon v-show="dialogOptions.fullscreen">fullscreen_exit</v-icon>
<v-icon v-show="!dialogOptions.fullscreen">fullscreen</v-icon>
</v-btn>
<span>{{ dialogOptions.fullscreen?'Fullscreen off':'Fullscreen on' }}</span>
</v-tooltip>
<v-tooltip :close-delay="0" bottom>
<v-btn slot="activator" @click="dialogOptions.dialogRef.close()" icon>
<v-icon>close</v-icon>
</v-btn>
<span>Close</span>
</v-tooltip>
</v-toolbar>
</div>
</component>
</conditional-wrapper>
@LinusBorg thanks man! That was a cool solution!! 馃槑
Most helpful comment
A small generic functional component can easily achieve a conditional wrapper element: