Slot templates inside logic templates fail to render
Version
3.2.33
Reproduction link
Steps to reproduce
Put one or more templates with a named slot inside a template with logic like v-if
.
What is expected?
For the slots to conditionally render
What is actually happening?
Compiled with problems:
...
Module build failed (from ./node_modules/vue-loader/dist/templateLoader.js):
Error: Codegen node is missing for element/if/for node. Apply appropriate transforms first.
at assert (.../@vue/compiler-core/dist/compiler-core.cjs.js:508:15)
Working through the compatibility build to migrate from vue2 ran into this failure.
all templates should be top level
from :
<BaseLayout>
<template #header>
<h1>Here might be a page title {{myProp}}</h1>
</template>
<template v-if="myProp">
<template #default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template #footer>
<p>Here's some contact info butts</p>
</template>
</template>
</BaseLayout>
To:
<BaseLayout>
<template #header>
<h1>Here might be a page title {{myProp}}</h1>
</template>
<template #default v-if="myProp">
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template #footer v-if="myProp">
<p>Here's some contact info butts</p>
</template>
</BaseLayout>
For simple logic that seems fine but I have at least a few use-cases where consolidating the logic is a big help for readability.
Something like:
<BaseLayout>
<template #header>
<h1>Title That Persists</h1>
</template>
<template v-if="certainCondition">
<template #default>
<p>Initial content</p>
</template>
<template #footer>
<button>Control for this chunk</button>
</template>
</template>
<template v-else>
<template #default>
<p>Secondary content</p>
</template>
<template #footer>
<button>Another action</button>
</template>
</template>
</BaseLayout>
That would have been nice, but it's not a supported syntax.
<BaseLayout>
<template #header>
<h1>Title That Persists</h1>
</template>
<!-- Certain Condition -->
<template #default v-if="certainCondition">
<p>Initial content</p>
</template>
<template #footer v-if="certainCondition">
<button>Control for this chunk</button>
</template>
<!-- Fallback -->
<template #default v-if="!certainCondition">
<p>Secondary content</p>
</template>
<template #footer v-if="!certainCondition">
<button>Another action</button>
</template>
</BaseLayout>
As @lidlanca pointed out, you should write the v-if
multiple times for this to work. Using multiple templates like that creates ambiguity for the default slot and therefore cannot be supported.