Forget $compile in Angular 2

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.

Show your support

Clapping shows how much you appreciated Suguru Inatomi’s story.