Angular + Web Components

I’ve finished my first experiment.

33.5 KB gzipped (107 KB uncompressed).

Hello World Angular element without NgZone.

The browser platform, 1 element, 1 Angular module, 1 component.

Next up, renderComponent based minimal Angular element bundle.

Second experiment.

8.82 KB gzipped (24.5 KB uncompressed).

Hello World Angular element using renderComponent.

No NgZone, no platform, no Angular module, 1 element, 1 component.

Third experiment.

13.5 KB gzipped (40 KB uncompressed).

Zippy Angular element using renderComponent and a feature render module.

No NgZone, no platform, 1 Angular module, 1 element, 1 component, 1 directive, 1 pipe.

Note: Still need to implement Shadow DOM and content projection.

So I upgraded to ng9 today. I didn’t yet put out ngzone and the other stuff yet, so I actually have an increase in bundle size, almost 30%. But obviously that will change, so tomorrow I’m going to get rid of ngzone. @LayZee, thanks for your examples, I will definitely take a look at them

So here I try to remove ngmodules and zone.js, and hit a wall now:

forms.js:1067 Uncaught Error: Cannot inject Renderer2 when the application uses Renderer3!
at getOrCreateRenderer2 (forms.js:1067)
at injectRenderer2 (forms.js:1077)
at push…/…/node_modules/@angular/core/ivy_ngcc/fesm5/core.js.Renderer2.NG_ELEMENT_ID (primeng-button.js:61)
at getOrCreateInjectable (core.js:26019)
at Module.ɵɵdirectiveInject (forms.js:4714)
at NodeInjectorFactory.NgClass_Factory [as factory] (core.js:17044)
at getNodeInjectable (core.js:26211)
at instantiateAllDirectives (core.js:30663)
at createDirectivesInstances (core.js:30054)
at Module.ɵɵelementStart (forms.js:4860)

As you can see, this gives me an error related to a primeng component, but I am using primeng@9.0.0-rc4, which is (as they claim) Ivy compatible. And honestly I don;t understand how this injectRenderer2 got there at all. I don’t have that many dependencies (only ngrx and primeng), and I already took care of almost all of them, and this error just ruins it all.

It appears that the problems lies in the implementation of the NgClass directice (what a surprise!). Here is the line of code that causes trouble:
private _renderer: Renderer2
Well, NgClass uses Renderer2 (obviously), but somehow Ivy does not permit to use Renderer2 because it already uses Renderer3! Any ideas on How to bypass this problems?

There is no Renderer3 in the public API, only a new implementation. The interface is the same. Why do you think NgClass is broken? A lot changed with styles in v9. PrimeNG might have relied on old, broken behavior.

Fourth experiment.

21.1 KB gzipped (65.9 KB uncompressed).

Hello World Angular element using hacked createCustomElement without platform and NgZone.

1 element, 1 component.

Hey, actually it’s NgClass that is broken - here is a working reproduction. I know there is no Renderer3 in public API, but the injector somehow tries to pull Renderer2 into the app built with Ivy and throws an error (that is how I perceive it, might be completely wrong).

When we use renderComponent, we don’t have a platform such as the one usually created by platformBrowser in main.ts.

There are a lot of platform level dependencies we need to provide ourselves to be able to use the declarables exported by CommonModule and other platform level dependencies needed to run dependently and securely in the browser such as a Sanitizer.

We should pass a DomSanitizer to the sanitizer option of renderComponent. We need to provide platform level dependencies normally provided by platformBrowser, BrowserModule, and ApplicationModule.

Hi Armen,
Im trying to pass input to my webcomponent using @Input directive and using a typescript setter inside the component to detect the change and call the function. But Im having issues with IE. It is not detecting the input hence not calling the function inside the setter. I’ve added ElementZoneStrategy as well but still facing this issue(only in IE). Can you suggest some workaround for this to work in IE.

Hi, I would love to help, but I need more info. Does change detection not work at all? Or is the problem only with that input? What is the name of the input property? Is the input getter/setter?

Change detections are working fine. Only having problems with input directive. Working fine in all browsers except IE.
input name : ab2input

in component.ts
@Input(‘ab2input’) set ab2input(val:any){
//function call

Hi Arman,
I’ve tried changing the input name with only small case chars and it is working in IE. Not sure whether this really caused the issue.

I have posted some questions in stackoverflow regarding angular-elements but didnot get any response. Questions regarding angular-elements are not getting much attention in stackoverflow. If possible can you check these


Hi, so the thing is (I believe I mentioned it in the article, if not, I have to add) that when you pass data to web component via attributes (inputs), the names get mapped from camelcase to kebabcase, here: if we have a ‘my-web-component’ with an inout that say ‘firstName’, we should have it like this:

<my-web-component first-name="Manoj"></my-web-component>

For example. This mapping is automatic, you can have any Input property name you want, just remember about the mapping (it is done so to adhere to valid HTML standards, html attributes cannot be camlecase, only kebabcase)

Thanks Armen,
It will be very helpful if you provide your thoughts on these questions.

@manojR as per the first question, did you use the webcomponents shim from mentioned in the article?

@armen NO. I’ve used document-register-element 1.8.1 and it is working fine. As it comes along with @angular/elements package it was easier to use.
But versions above and below 1.8.1 doesn’t support es5 output.

The document-register-element package has some issues, Better use the shim I provided in the article, it definitely works. I had the same problem as you back when I was setting my project up, and changing to webcomponents/shim fixed all the issues.