Skip to main content

Portals & Teleportation

Evolve's template interface doesn't support arbitrary reordering of the ui tree like other frameworks do, because it requires your app to use Structural Identity to figure out which elements are linked to various scopes.

In other languages/frameworks you an manipulate the ui tree however you like, whenever you like. For example, with HTML you could define a piece of dom and then re-parent it at will.

The primary use case for wanting to re-order the tree is to move groups of elements to other places. Luckily, in almost all cases, you the author of the UI know where there other places are in your app.

To address this usecase, Evolve has a feature called teleport. It does exactly what it sounds like: it teleports hierarchies of elements into other places in your app.

A good example of this is a modal dialog. You have all of the data/state for this in a template you've authored, but you want to actually render the modal on a higher layer than the currently executing template would normally be rendered at. You can solve this easily with a teleport.

The second piece of the puzzle is the portal directive. Once you have teleport-ed your content somewhere, you will need to render a portal of the same name to actually display the content. If a teleport doesn't find a matching portal at the end of the frame, its contents will end up in purgatory, where they are considered active but will not layout or render.

template PortalExample render {

state bool isConfirmed;

// there are two parts to the syntax, the first is what you want teleported. In this case we want to show our
// 'Confirm' button in a modal overlay. However we haven't yet rendered the modal layer because it natually must
// appear on top of the rest of our UI.
teleport->("Modal") {
// any bindings will run at this point and all context is lexical
if(!isConfirmed) {
Button("Confirm", mouse:click = isConfirmed = true);
}
}

}

//... later in another template we will render the modal itself

template Portal render {

// this is where our Button element actually renders.
// we are able to use the button in the binding scope of our template but it is somewhere completely different in the hierarchy
// important! this also means that it will be laid out and styled as though its parent were the parent of the portal,
// it is completely disconnected from its original usage except for bindings!
render portal("Modal");

Portals

Portals are kind of like a reverse slot. It is a way to inject content elsewhere in the app while still having a binding scope that is local to the element. A great example of this is a tooltip or a modal dialog.