maoberlehner / dynamic-vue-layout-components

This is an example project for the following article: https://markus.oberlehner.net/blog/dynamic-vue-layout-components/
MIT License
43 stars 13 forks source link

How to add more slots in LayoutDefault.vue #3

Open aronzillo opened 4 years ago

aronzillo commented 4 years ago

I want to use a LayoutDefault template like this:

<template>
  <div class="LayoutDefault">
    <nav class="tw-navbar">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>

      <div class="tw-slogan">
        <slot name="slogan"></slot>
      </div>
      <div class="tw-buttons">
        <slot name="buttons"></slot>
      </div>
    </nav>
    <main class="LayoutDefault__main">
      <slot/>
    </main>
    <footer class="LayoutDefault__footer">
      &copy; Awesome Company
    </footer>
  </div>
</template>

Now in Home.vue I put this code but markup inside slot is not renderer, what I do wrong?

<template>
  <layout name="LayoutDefault">
    <div class="top-header">
       <template slot="slogan">
          It does not work
       </template>
       <template slot="buttons">
           Some dummy text
       </template>
    </div>
    <div class="Home">
      <h1>Home</h1>
      <p>
        Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
        eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
        voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
        clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
        amet.
      </p>
    </div>
  </layout>
</template>
maoberlehner commented 4 years ago

<template slot="slogan"> and <template slot="buttons"> are nested inside <div class="top-header">. So you basically say put It does not work into a slot named slogan of <div class="top-header"> but divs don't have slots.

Try this:

<template>
  <layout name="LayoutDefault">
     <template slot="slogan">
        This should work
     </template>
     <template slot="buttons">
         Some dummy text
     </template>
    <div class="Home">
      <h1>Home</h1>
      <p>
        Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
        eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
        voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
        clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
        amet.
      </p>
    </div>
  </layout>
</template>
aronzillo commented 4 years ago

Still not working properly 😢 I have this markup in LayoutDefault.vue

<template>
    <div class="h-screen flex font-sans">
        <div :class="sidebarOpen ? 'block' : 'hidden'" class="fixed z-20 inset-0 bg-black opacity-50 transition-opacity lg:hidden"></div>
        <div :class="sidebarOpen ? 'translate-x-0 ease-out transition-medium': '-translate-x-full ease-in transition-medium'" class="fixed z-30 inset-y-0 left-0 w-64 px-8 py-4 bg-gray-100 border-r overflow-auto lg:static lg:inset-auto lg:translate-x-0">
            <div class="-mx-3 pl-3 pr-1 flex items-center justify-between">
                <span>
                    <img class="h-9 w-9" src="https://image.flaticon.com/icons/svg/1077/1077874.svg" height="36px" width="36px">
                </span>
                <button v-on:click="sidebarOpen = false" class="text-gray-700 lg:hidden" type="button">
                    <svg class="h-6 w-6" viewBox="0 0 24 24" fill="none">
                        <path
                            stroke="currentColor"
                            stroke-width="2"
                            stroke-linecap="round"
                            d="M6 18L18 6M6 6L18 18"
                        />
                    </svg>
                </button>
            </div>
            <nav class="mt-8">
                <h2 class="text-xs font-semibold text-gray-600 uppercase tracking-wide">Docs</h2>
                <div class="mt-2 -mx-3">
                    <router-link :to="{ name: 'home' }" class="flex justify-between items-center px-3 py-2 bg-gray-200 rounded-lg">
                        <span class="text-sm font-medium text-gray-900">Home</span>
                    </router-link>
                </div>
            </nav>
        </div>

        <div class="flex-1 min-w-0 flex flex-col bg-white">
            <div class="flex-shrink-0 sm:border-b-2 sm:border-gray-200">
                <header>
                    <div class="px-6">
                        <div class="flex justify-between items-center py-3 border-b border-gray-200">
                            <div class="flex-1 min-w-0 flex">
                                <button v-on:click="sidebarOpen = true" class="text-gray-600 lg:hidden">
                                    <svg class="h-6 w-6" viewBox="0 0 24 24" fill="none">
                                        <path
                                            stroke="currentColor"
                                            stroke-width="2"
                                            stroke-linecap="round"
                                            d="M4 6h16M4 12h16M4 18h7"
                                        />
                                    </svg>
                                </button>
                                <div class="flex-shrink-1 ml-3 relative w-64 lg:ml-0">
                                    <span class="absolute inset-y-0 left-0 pl-3 flex items-center">
                                        <svg class="h-6 w-6 text-gray-600" viewBox="0 0 24 24" fill="none">
                                            <path
                                                stroke="currentColor"
                                                stroke-width="2"
                                                stroke-linecap="round"
                                                d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
                                            />
                                        </svg>
                                    </span>
                                    <input class="block w-full rounded-lg border border-gray-400 pl-10 pr-4 py-2 text-sm text-gray-900 appearance-none leading-tight focus:outline-none focus:bg-white focus:border-blue-500 placeholder-gray-600" type="text" placeholder="Search">
                                </div>
                            </div>

                            <div class="ml-6 flex-shrink-0 flex items-center">
                                <button>
                                    <svg class="h-6 w-6 fill-current text-gray-500" viewBox="0 0 512 512">
                                        <path
                                            stroke="currentColor"
                                            stroke-width="2"
                                            stroke-linecap="round"
                                            d="m450.201 407.453c-1.505-.977-12.832-8.912-24.174-32.917-20.829-44.082-25.201-106.18-25.201-150.511 0-.193-.004-.384-.011-.576-.227-58.589-35.31-109.095-85.514-131.756v-34.657c0-31.45-25.544-57.036-56.942-57.036h-4.719c-31.398"
                                        />
                                    </svg>
                                </button>
                                <account-dropdown class="sm:block sm:ml-6"></account-dropdown>
                            </div>
                        </div>
                        <div class="flex items-center justify-between py-2">
                            <div class="sm:flex sm:items-center">
                                <h2 class="text-2xl font-semibold text-gray-900 leading-tight">
                                    <slot name="header-title">My custom title</slot>
                                </h2>
                            </div>
                            <div class="flex">
                                <slot name="header-buttons"></slot>
                            </div>
                        </div>
                    </div>
                </header>
            </div>

            <div class="flex-1 overflow-auto bg-gray-100">
                <main class="p-3 flex">
                    <slot></slot>
                </main>
            </div>
        </div>
    </div>
</template>

Calling the slot from the Home.vue I don't know why it doesn't work

<template>
    <layout name="LayoutDefault">
        <div class="flex items-center justify-between py-2">
            <template slot="header-title">
                New title
            </template>
            <template slot="header-buttons">
                <button>1</button>
                <button>2</button>
            </template>
        </div>
        <div class="Home" >
            <h1>Home</h1>
            <p>
            Eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
            voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
            clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
            amet.
            </p>
        </div>
    </layout>
</template>
maoberlehner commented 4 years ago

You can't nest your <template slot="header-title"> and <template slot="header-buttons"> inside of another <div>. A slot attribute is telling Vue to put the element with the attribute inside the slot of its parent element.

<div class="flex items-center justify-between py-2">
  <template slot="header-title">
    New title
  </template>
  <template slot="header-buttons">
    <button>1</button>
    <button>2</button>
  </template>
</div>

In this case above, the parent element of <template slot="header-title"> is the <div>. This <div> has no slots. So the <template slot="header-title"> disappears.

As I already wrote in my first answer, you have to remove the wrapper <div>.

<template>
    <layout name="LayoutDefault">
        <template slot="header-title">
            New title
        </template>
        <template slot="header-buttons">
            <button>1</button>
            <button>2</button>
        </template>
        <div class="Home" >
            <h1>Home</h1>
            <p>
            Eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
            voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
            clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
            amet.
            </p>
        </div>
    </layout>
</template>

Now in this example the parent is the <layout name="LayoutDefault">.

Please consider to create a CodeSandbox with a reduce test case to make it easier to help you. Thx!

rtobescu commented 2 years ago

I know it's a couple of years late, but I'm also experiencing the same issue. I've setup a sandbox which is here. I've updated the main element in LayoutDefault.vue to

  <main class="LayoutDefault__main">
    <slot/>
    <slot name="second"/>
  </main>

and the pages to

<layout name="LayoutDefault">
  <template #default>
    <div class="About">
      <h1>Default</h1>
    </div>
  </template>
  <template #second>
    <div class="About">
      <h1>second</h1>
    </div>
  </template>
</layout>

And I still can't get the second slot to render