Marmicode
Blog Post
Younes Jaaidi

A New Syntax for Angular Templates

by Younes Jaaidi • 
Mar 11, 2019 • 4 minutes
A New Syntax for Angular Templates

Angular Templates & Time To First Commit

One of my favorite things about Angular is how the template is just a simple HTML file.

This is really great; especially if you care about Collective Ownership. With some basic HTML knowledge, anyone can contribute to the application’s development: other teams, external web designers… or even the Product Owner! Why not!?

In other words, using HTML templates reduces the TTFC (Time To First Commit) which is the average time it takes for someone new in your team to make his first change.

Tired of Importing Modules

Now, the thing that I don’t like that much about Angular is how the template is just a simple HTML file. Wait wait wait! Let me try to explain!

In Angular, every component, directive or pipe has some kind of selector (or name) that we can use in our components’ templates. When the template is compiled, the implementation is resolved depending on the component’s module imports.

To interpret the content of a template, the runtime needs to know what component and directives to apply to the element and what pipes are referenced by binding expressions. The list of candidate components, directives and pipes are determined by the NgModule in which the component is declared.

The official and complete explanation is here: https://github.com/angular/angular/blob/master/packages/compiler/design/architecture.md#the-selector-problem

The problem with this approach is that we need to import the right module every time we want to use another component, a directive or a pipe.

Which Module Should I Import Again?

A while ago, I was explaining reactive forms during a training so I wrote this:

<form [formGroup]="sandwichForm">

it produced the expected error Can’t bind to ‘formGroup’ since it isn’t a known property of ‘form’ and I explained that we have to import ReactiveFormsModule, then someone asked:

How did you know which module you should import?

That’s when I realized that for someone very new to Angular, this was not intuitive at all. That’s also when I noticed that the related question on stackoverflow had more than 770 000 views: https://stackoverflow.com/questions/39152071/cant-bind-to-formgroup-since-it-isnt-a-known-property-of-form

Ng VDom

I started thinking about a new way of writing Angular templates so I stumbled upon this brilliant initiative called Ng-VDom

export class AppComponent extends Renderable {
  render() {
    return (
      <h1>Hello World!</h1>
    )
  }
}

But still, it was not exactly what I was looking for as I just wanted a new way for writing templates and not a new way of rendering components.

A New Way of Writing Templates

That’s when I got inspiration from htm which stands for Hyperscript Tagged Markup. I liked how it was simply using standard tagged templates so I came up with the ngMarkup tagged template which works like this:

@Component({ selector: 'mc-greetings', template: `<h1>Hi {{ name }}</h1>` }) export class Greetings { @Input() name: string; } @Component({ selector: 'mc-app', template: ngMarkup` <${Greetings} name="foo"></${Greetings}> <${Greetings} name="john"></${Greetings}> ` }) export class AppComponent {}

The working example’s source code is here: https://github.com/yjaaidi/ng-experiments/tree/ng-markup

The main advantage of this syntax is that the components, directives, and pipes used in the template are explicitly imported.

What’s Next?

Surviving AOT

The current implementation doesn’t survive AOT as it would need a pre-compiler or upgrading IVY compiler: ngtsc.

Getting rid of explicit ngModule declarations & exports

As you can see in the given example’s source code, the components, directives, and pipes are still explicitly declared or imported in AppModule.

In order to fix the last issue, it would be nice to let ngMarkup import the dependencies in the component’s local scope at compile time. There’s a great article about this here: https://blog.angularindepth.com/angular-revisited-tree-shakable-components-and-optional-ngmodules-329a4629276d by Lars Gyrup Brink Nielsen.

I was looking forward to using the someday-maybe-upcoming deps property in component configuration which appears in this Pull Request https://github.com/angular/angular/pull/27481 by Minko Gechev ... but the work on this feature seems to be stalled for the moment.

Feedback

I am really looking forward to hearing from any feedback about this kind of syntax.

Does it sound easier to read and maintain? Is it too hacky? Do you think it somewhat violates the separation of concerns or is it fair?

IDEs To The Rescue

Luckily, lately, I was explaining the exact same thing and the error didn’t happen.

Actually, I used WebStorm’s Angular module auto-import without noticing.

WebStorm Auto-Import Module

Maybe in some near future, IDEs magic & Angular Language Service might make this whole post and experiment useless 😅

WebStorm Auto-Import Component Module