Open boardend opened 4 years ago
This would be because the child <router-view>
is no longer nested within the parent <router-view>
when portalled: the parent hierarchy changes (https://portal-vue.linusb.org/guide/caveats.html#known-caveats) if your <portal-target>
is not rendered within your parent <router-view>
container.
One workaround would be to use named <router-view>
s, and set the "child" route to be targeted to that name view (https://router.vuejs.org/guide/essentials/named-views.html#named-views)
@tmorehouse thanks for your quick reply!
I've just tried out your proposed workaround and it seems that nested views cannot use named views from "upstream" routes/components. It only works when the named <router-view>
is defined inside the parent component.
<router-view name="modal"/>
of Page2.vueThere is a way to force a particular parent on a component... it requires manual mounting though (note I haven't tested this example code, but I have done similar for other things):
<template>
<div>
<router-view ref="parentView" />
<div ref="portalTarget" />
</div>
</template>
<script>
import { PortalTarget } from 'portal-vue'
export default {
mounted() {
const parentComponent = this.$refs.parentView
const childElement = this.$refs.portalTarget
const pt = new PortalTarget({
el: childElement,
parent: parentComponent,
propsData: {
name: 'modal-portal'
}
})
// Ensure the portal target is destroyed
this.$once('hook:beforeDestroy', () => pt.$destroy())
}
}
</script>
EDIT:
This will probably not work since <router-view>
is a functional component (which doesn't have a Vue this
instance).
You would need to render the portal target inside of the parent router-view, and pass the top route's parent instance to the parent
of the dynamically added portal-target
. Or one could manually mount the child router-view
and pass an explicit parent to it.
As you already stated, I couldn’t get the functional router-view
component mounted with a manually set parent component. And when I tried mounting it with a wrapper component (as proposed here https://stackoverflow.com/questions/54239343/how-do-you-unit-test-a-vue-js-functional-component-with-a-render-function-that-r/54277077#54277077) Vue Router didn’t pick up the router-view
element.
I’m currently perusing a solution without Portal-Vue which works, but is not as nice if I were able to send the route component to the desired location.
If there isn’t a nice/easy solution to get Vue Router and Portal-Vue working together, we should use this issue to add some notes to the Portal-Vue Known Caveats.
This is indeed a caveat, which is a consequence of the $parent
caveat.
<router-view>
internally walks the $parent
chain to find out how many (if any) parent <router-view>
components there are.
We should indeed add a note to the docs.
Also note that this is not a problem in vue-simple-portal, and will also not be an issue with Vue 3's native <teleport>
component.
I've switchd to vue-simple-protal which indeed fixes this problem. Added a small note to the docs anyway, see https://github.com/LinusBorg/portal-vue/pull/307
Thanks! Will close then docs change has been deployed.
Version
2.1.7
Reproduction link
https://codesandbox.io/s/great-elgamal-y285j
Steps to reproduce
Use
<router-view />
with nested routes inside a<portal>
to render the nested routes somewhere else in the app (e.g. a lightbox modal that is logically a child of some other component/route, but should be rendered somewhere close to the root component).What is expected?
The route matching will work the same, no matter if the
<router-view />
is inside a<portal>
or not.What is actually happening?
When inside a
<portal>
, the nested route gets replaced with the parent route from where the<portal>
was used.