teleport should be reactive
What problem does this feature solve?
One of the main features of Vue is to control, what components are displayed. Teleport however requires that an element is mounted before the teleport tag is mounted. If for some reason the teleport target is removed but mounted again, the teleport does not work.
What I want is: If teleport is enabled (:disable="false"), then look for the element to be teleported to. return error or warning if not found. teleport if found.
This feature would make teleport a lot more easy to use, because it fits better into an Vue environment where everything is reactive.
As for a use-case: I currently want to teleport an input-field to a sidebar (https://www.primefaces.org/primevue/sidebar) that is displayed on small displays. The sidebar is displayed when I click on the inputfield. Even if I make sure that the teleport is enabled after (up to 10sec) the sidebar is displayed, the teleport fails silently.
What does the proposed API look like?
If teleport is enabled (:disable="false"), then look for the element to be teleported to. return error or warning if not found. teleport if found.
It has a wierd workaround, that I found seconds before giving up:
<Sidebar v-model:visible="showMobile" position="top">
<div id="mobileTarget"></div>
</Sidebar>
<teleport
v-if="ready"
to="#mobileTarget"
:disabled="disableTeleport"
>
....
@focus="switchToMobile"
....
</teleport>
data() {
return {
showMobile: true, //Initially the teleporttarget is present
ready: false, // Initially teleport is not created.
disableTeleport: true,
};
},
mounted() {
this.ready = true; //Delays the mount, therefore teleport will not throw an error, because teleporttarget is still present
this.showMobile = false; //removes teleporttarget, so its not displayed
},
methods:{
allowTeleportToMobile(): boolean {
return this.breakpoint === "xs" || this.breakpoint === "sm";
},
switchToMobile() {
if (this.allowTeleportToMobile && !this.showMobile) {
this.showMobile = true; // first make the teleporttarget available
this.ready = false; // remove the teleport
setTimeout(() => { //wait a little (it doesn't work without setTimeout
this.disableTeleport = false; //enable the teleport
this.ready = true; // render it ==> now it teleports properly.
}, 1);
}
},
}
But its a very verbose and ugly workaround if you ask me. The teleport should check for the existence of the target, when activated. I would even propose that the target can be a vue component it self, but it would certainly help if that mounted requirement is gone.
Don't know what exactly you were proposing with the key. I only know it from lists (v-for), which isn't my current use-case.
@telion2 the work around with key would be adding the :key
attribute to the component (or teleport, not sure exactly which is most appropriate @posva). If you change the key, Vue will register that when diffing and that will force a re-render
Its not a feature that has to be exclusively used with v-for
or iteration over data. It can be used in any situation.
Have a very similar usecase — using portal-vue
to make it work — but would be nice if Teleport
supported these scenarios.