TL;DR
- Forget about
$compile
- Use
innerHTML
and DOM APIs
$compile
in Angular 2
I wrote an article that explain “how to load a HTML template with using dynamic component creation.”
Since Angular 2, $compile was dropped. There are no ways to insert HTML fragments into the component view except using innerHTML. But if we could create a component and load it…? Yes, we can do it! This post will explain about dynamic HTML projection in Angular 2 with dynamic component creation.
How did I ?
Before @NgModule
introduced, I used ViewContainerRef
and RuntimeCompiler
with a dynamic component factory.
Dynamic component factory is a just function that calls Component()
decorator function to create decorated class object dynamically.
private createDynamicComponent(selector, template) {
const metadata = new ComponentMetadata({
selector,
template,
});
const cmpClass = class _ { };
return Component(metadata)(cmpClass);
}
And then, I passed the class to RuntimeCompiler
and get ComponentFactory
.
this.compiler
.compileComponentAsync(this.createDynamicComponent(selector, template))
.then(factory => {
this.vcRef.clear();
this.vcRef.createComponent(factory, 0, injector);
});
After NgModule
In Angular 2.0.0-rc.6, many APIs including Compiler#compileComponent
were removed as deprecated API. Now, every component is belonging to its NgModules as declarations, and every compilation starts on the module.
Important thing: NgModules are compilation context.
That means I no longer be able to compile components separately because any compilations needs a module.
Of course, then I had an idea; dynamic component compilation with dynamic module creation.
If you are interested in the idea and my challenge, see this code.
https://github.com/laco0416/angular2-component-outlet/blob/master/src/component-outlet.ts#L70-L99
I tried that and it seems succeeded, but it has a big problem: AoT.
RuntimeCompiler is dead
Ahead of Time compilation is a powerful feature of Angular 2 to gain drastic performance improvement. It allows us to compile templates at the build time and reduce dependency on @angular/compiler
package. It significantly affects to app bundle size if we use tree-shaking. why? Because then our app doesn’t have RuntimeCompiler
. As all compilation finished in offline, a compiler is not needed in runtime.
AoT compilation brings many benefits to us:
- Small payload bundle
- Fast bootstrapping
- Template error detection
So, I chose AoT and threw away $compile
.
Use innerHTML
and DOM APIs
Instead of $compile
, I decided to use innerHTML
and DOM APIs to implement something like directive
or Custom Elements.
Most of our directives may be reproduced with native DOM. For example, we can create pseudo-routerLink in a dynamic HTML.
It’s very grunt code, but works well. We should go on the right way of Angular and Web standards.
Summary
Angular 2 is stable now. We should throw away tricky ways. Keep our applications AoT-friendly and optimizable. Follow the right Angular way.