Angular Elements and NgZone; Dynamic Content-Projection Solution

Akash Bavale
The Startup
Published in
5 min readAug 9, 2020

Content Projection is a way to insert a shadow DOM inside your Angular component. But unfortunately, we don’t see a dynamic <ng-content> available anywhere. This article is a walk-through to how to create a dynamic content projection solution using already available packages viz. Angular Elements and NgZone, and use it intuitively in your application.

Using Angular Elements, you can create Angular components which can be used inside or outside of the Angular application. But its better use, is inside the Angular application, to create a native web component. We can send these components to a child component gracefully sanitizing it.

To have a better understanding of how this works, let us setup an Angular project. You can download the example application source code from here:

Lets start with the prerequisites needed for the angular elements to work. Along with rxjs package, remember to have a rxjs-compat dependency in your package.json, in order to your Angular elements package to work properly.

package.json

In this paradigm, we have created a simple component, lets call it Messenger. It will only accept a input parameter called message. Now lets call it in the traditional way in our app.component.html like below:

app.component.html

And it outputs the string that is assigned to it. Now lets see how to convert this component into a native web component. But before that let’s see how a normal native web element can be called. The setTimeout is used to simulate a synchronous behavior.

app.component.ts
app.component.html

And that does it! You can see the output “This is a native web element”. But similarly when we integrate our component in the content it gives us following console warning.

app.component.ts
HTML sanitizing warning

Okay, lets sanitize it then! we use DomSanitizer from @angular/platform-browser. Sanitizing is needed in order to tell html that we trust this particular piece of code.

app.component.ts

Well, the console warning goes away, but we still see nothing! The reason is that it gets rendered as html code but it is not recognized as html element. Angular does not consider this after our application is loaded because the compilation of templates and the part where it understands your component is done by then. Hence we see a blank page. And Angular Elements fixes this very problem. It allows us to take our angular component and put it into a virtually encapsulated self bootstrapping html element.

Let’s go ahead and install @angular/elements. In order to create a new native web element. We import createCustomElement from @angular/elements as below:

app.component.ts

This method takes two inputs, the reference of the component of which we need to create native element of and the injector, which we import from @angular/core . Furthermore, we define a new element with the first parameter as the new name of our native element ‘my-messenger’ (doesn’t have to be same your components selector, but can be) and second parameter as our referenced messengerElement. Now we have our native element ready, we can use it as below:

app.component.ts

and voila! we see the output :

output

Bonus: NgZone

what role does NgZone play in this? Let’s understand.

Let’s Suppose that we have a use case to use a native element in our component. In this example, we have a button which has click event and we need to pass it as a sanitized element. But it has some drawbacks as it is a native element.

app.component.ts

Here, you may notice that we are using (click) event from Angular. Although, we see a button on the screen but it has no effect even when we click it. The click event is not triggered because we are trying to trigger an angular event from a native element. Okay! then lets go ahead and change the angular event to a normal native button onclick.

app.component.ts

But now we have an error saying, it does not recognize the method. So workaround for this is defining a key in the Window Object and then it can call the angular method as shown below:

app.component.ts

And that does the trick! You can see that the alert shows up!

Alert

Again, it only shows the alert. But what we are doing is just calling an angular method inside a non-angular element. Hence, it won’t work as expected. So we can now introduce NgZone, in order to counter these problems. It will call this method as angular method running from outside of the application.

app.component.ts

Again, this will do the same thing but now this is simulating an angular method.

UseCase: Have a look at point number 8 and 9

That’s all Folks!

--

--

Akash Bavale
The Startup

Programmer, Movie Buff, Photo Enthusiast, Aspiring Artist and an Atheist. Visit me on https://bavaleakash.github.io/