Issue with multiple slots in persistence layout.
See original GitHub issueI have used a persistence layout where two slots (scoped slots) are present. Now I can’t use that multiple scoped slots in my pages to push content in a layout. Any workaround on this?
Here is something that I was trying to do.
<template>
<main>
<slot name="header"/>
<slot/>
</main>
</template>
<script>
export default {
name: "Layout",
}
</script>
and my page is something like this:
<template>
<div>
page content
</div>
</template>
<script>
export default {
name: "Page",
layout: (h, page) => h(Layout, [page])
}
</script>
How can I pass the content of the header
slot? I can do the following, as mentioned in https://github.com/inertiajs/inertia-vue/pull/87#issuecomment-536436890
export default {
layout: (h, page) => {
return h(Layout, {
scopedSlots: {
header() {
return h('span', 'Header')
}
}}, [page])
},
}
But I have not just a simple “Header” text in span. So I guess it’s not that easier to write the whole content of the header in that way.
Any suggestion what should I do?
Issue Analytics
- State:
- Created 3 years ago
- Reactions:2
- Comments:30 (6 by maintainers)
Top Results From Across the Web
Build Modern Laravel Apps Using Inertia.js: Persistent Layouts
@abdosaeedelhassan +1 on this. I'm using multiple named slots and haven't found a way around to use persistent layouts.
Read more >Laravel jetstream inertia persistent layout - Stack Overflow
If the header slot is in AppLayout aka the persistent one, you cannot use this way (because there is no slot yet?
Read more >Structuring Layouts in InertiaJS applications - YouTube
Structuring Layouts in InertiaJS applications. 4.2K views 2 years ago. Constantin Druc. Constantin Druc. 3.21K subscribers. Subscribe.
Read more >Pages - Inertia.js
Persistent layouts. While it's simple to implement layouts as children of the page components, it does force the layout instance to be destroyed...
Read more >Layouts with Vue.js - How to Create Dynamic Layout ...
Static layout wrapper components. Next we take a look at how we can use an ordinary component, containing one or multiple slots for...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
For anyone who stumbles across this issue, I was able to work around the lack of slots by using this package: https://github.com/LinusBorg/portal-vue
I have
portal-target
components in my persistent layout where i’d normally use a conventional vue named slot. Then in my inertia pages I can push my content into those portal targets using<portal to="target-name">
With this setup my code splitting works again since my inertia page component is invoking PersistentLayout, obviously you lose some of the vue goodness like scopedProps but most of your state should be in a vuex store anyways 😄
here is a simple example:
Sorry for not replying to this earlier (like I did on solution referred to above).
While the above solution indeed works, is only a partial & programmatic workaround to this issue by intercepting Vue’s
render
cycle. While it would allow you to use multiple slots, it’s still far from perfect, and it’s not exactly what I would call the ‘great developer experience’ that most of us are used to from working with Vue.I did some source diving and looked into how to solve this earlier. Essentially, the way that persistent layouts work in Inertia is like this:
render
-method gets hit by Vue itself.layout
-property/function, which it then calls as if it was the Vuerender
method, passing in the already-rendered VNode/rendered instance as a 'child’While this might seem somewhat odd, it is actually quite cool, as this allow us to:
render
methodUnfortunately, this also means that while Vue at this point hasn’t finished rendering yet, but ** the “Page”-component is already done rendering** (which gets injected into the Layout), we cannot use template slots, unless defined programmatically like described previously.
If you think of it using Vue terms, it also makes sense, since you can (mostly) only pass slots into a child component, but you cannot pass child-slots into a parent… (In this case, the Layout is the parent component, and the Page is the child component)
Anyway, bad news aside, this got me onto another idea, which is to combine both approaches. Here’s what I ended up doing:
app.js
, I modified theresolveComponent
method to hijack Inertia before it hits Vue’s rendering process, and always inject the persistent layout on the “page”-component’s options (as theresolveComponent
method is simply how Inertia resolves the pages / the Vue component options that get used in the renderer described earlier)Complexity aside, this allows me to keep persistent things (such as notifications etc. and the user’s browser-interaction-state of it) in the “Persistent”-layout, and communicate to/from it using Vuex. The important thing to do here (IMO) is to keep the html markup/styling on the
Layout
component as much as possible, and to keep the “Persistent”-layout as markup-free as possible, as to provide an “invisible” layer of sorts. As far as solutions go, I think this is a pretty decent one.Long story short, or in case that wasn’t clear / copy and paste-able enough, here’s an example of how this would all get wired up:
app.js
VueXStore.js
Layouts/Persistent.vue
Layouts/Primary.vue
Pages/MyPage.vue
Hope it helps!