Back to the homepage
Angular

Teleportation in Angular

Teleportation, in the context of an Angular application, can be defined as a location change of a view fragment (in particular, moving it to another component), at the same time maintaining the data and event bindings of the original component. In a way, this is analogical to the content projection mechanism, but there is no need to save the parent-child relationship (e.g. a fragment can be teleported from a child to a parent).

The possibility of changing the elements’ position in the DOM tree, while preserving the original view-component bindings, is a natural Angular feature, resulting from the existence of a logical component tree (also at runtime), and its links to view templates in complete isolation from the DOM tree (changes in the DOM tree don’t influence changes in the logical component tree). 

img src: https://i.redd.it/kko442mrgim71.jpg

When is teleportation useful?

As mentioned above – when content projection itself is not enough and we have to locally reverse dependents in the component tree (a fragment of an ancestor view will depend on its descendant). An example could be a widget in the header of our site, which changes depending on the sub-page the user is on.

Ready-to-use solutions

https://material.angular.io/cdk/portal/overview 

A Portal which is a part of The Component Dev Kit (cdk), is a low-level mechanism used to create other angular material library elements (for instance overlays, which are used by e.g. dialogs). It’s made of 2 elements:

  • portal outlet, a “slot” for a view fragment, which we want to dynamically render,
  •  a view fragment we want to dynamically render (in the form of a reference to the DOM element, templateRef or to a component).

In order to make the teleportation work remotely, we need to create a mechanism that will transfer the view fragment from the right place to the outlet portal. This can easily be done by creating a service (singleton) that will simultaneously perform the registration (remembering) of the outlet and start and end the teleportation.

In our case, the registerPortalOutlet method takes a reference to the DOM element and creates our “slot” for the view fragment inside it. On the other hand, the unregisterPortalOutlet method destroys such a slot. The teleport and finishTeleportation methods are used to start and stop rendering the passed (as “portal”) view fragment. 

An example implementation on the content side to be teleported:

Using @ViewChild, we create a reference to the DOM element, from it we create an instance of the DomPortal class and pass it to our service. Don’t forget to finish the teleportation in ngOnDestroy.

An example implementation on the outlet portal side:

Analogically to the previous snippet, we create a reference to the DOM element that will be our “slot” for dynamic content and pass it to the service. Remember to destroy the slot in ngOnDestroy.

The implementation above presents a simplified version. Nothing stands in the way of implementing the possibility of multiple slots and identifying them with keys, as well as handling the case where we first provide a piece of UI to teleportation, and only then do the outlet registration. Instead of manually passing references to the service, we can create special directives to that end. 

https://github.com/ngneat/overview#Teleporting

The @ngneat/overview library provides us with a package of two directives:

  • teleportOutlet, which creates a “slot” at a given location,
  • *teleportTo, which is the content for teleportation.

Code snippet from teleportOutlet from the documentation:

Code snippet from *teleportTo from the documentation:

Custom implementation

If you don’t want to or can’t use ready-to-use solutions, it’s quite simple to create the whole mechanism from scratch. 

The ViewContainerRef will act as a “slot” for dynamic content.

Getting deep inspiration from the solution by @ngneat we create two directives:

An example of use looks like this:

Just like in the case of the example with @angular/cdk, the target solution is worth expanding with additional capabilities and security.

Conclusion

The repository, including all the implementations above, can be found at the following link:

https://github.com/mateusz-dobrowolski-va/angular-teleportation 

About the author

Mateusz Dobrowolski

Mateusz is a Typescript sympathizer with several years of experience in developing Angular applications.

Do you want to write articles for our blog together with us?
Join us and create valuable content for Angular fans with Angular.love!

Leave a Reply

Your email address will not be published. Required fields are marked *