2
votes

TL;DR: Is it possible to pass content to a specific slot of a component referenced in the parent component, from the child component?

I'm using the Vue Webpack Template which comes with Vue Router which provides the basis of a Single Page Application out of the box.

The issue I'm facing, is that I have a master layout, simplified below:

<template>
  <div id="app">
    <Nav/>
    <APageWithDifferentNav/>
  </div>
</template>

<script>
  import Home from "./components/views/Home";
  import APageWithDifferentNav from "./components/views/APageWithDifferentNav";
  import Nav from "./components/Nav";

  export default {
    name: "App",
    components: {
      Nav, Home, APageWithDifferentNav
    }
  };
</script>

And the nav component something like this:

<template>
  <div class="nav">
    <ul class="nav__list">
      <li class="nav__list-item">always show this nav item</li>
    </ul>
    <slot>
      <ul class="nav__list replace-this">
        <li class="nav__list-item">only show this</li>
        <li class="nav__list-item">if no slot</li>
        <li class="nav__list-item">content provided</li>
      </ul>
    </slot>
  </div>
</template>

<script>
  export default {
    name: "Nav"
  };
</script>

I want to be able to change a slot inside the Nav component, from within a view component.

For example, on a checkout or onboarding flow, you want to limit the navigation options shown to the user, and swap in other content to highlight where they are on their journey.

Is there a way for me to do this, without having to move <Nav/> inside every single page's template?

I've put together a more indepth code example to show what I'm after which you can view here.

Any help is much appreciated.

1

1 Answers

3
votes

AFAIK it's possible to pass slot contents only from parent to child.

Maybe you can obtain something similar using PortalVue, which enables rendering of DOM outside of the defining component, and using some v-if to disable the rendering of the default part.

But it seems an over-engineered solution for my taste. Sometimes it's just best to break the DRY principle (Don't Repeat Yourself) and recall the Nav component from every page, with variations where necessary, or to simply create a totally different page for those few views with a different nav, say /login, /logout, ... and at the top level use dynamic components with v-bind:is to select which view component to render (so you have one common App component for all the regular pages, using the regular Nav component, and one (or more as necessary) alternate LoginLogoutApp component using a different LoginLogoutNav).