Subscribe on changes!

Slot templates inside logic templates fail to render

avatar
Apr 18th 2022

Version

3.2.33

Reproduction link

sfc.vuejs.org/

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.

avatar
Apr 19th 2022

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>

Demo

avatar
Apr 19th 2022

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>
avatar
Apr 19th 2022

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>
avatar
Apr 19th 2022

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.

avatar
Apr 29th 2022

there's also v-else and if your layouts are that complex, maybe break them down into separate (child-) components