Angular Template Syntax

Victor Savkin
Angular
Published in
6 min readJul 25, 2016

--

Victor Savkin is a co-founder of nrwl.io, providing Angular consulting to enterprise teams. He was previously on the Angular core team at Google, and built the dependency injection, change detection, forms, and router modules.

In this blog post I will talk about the Angular 2 template syntax.

Input and Output Properties

Input and output properties are the public API of a directive. Data flows into a directive via its inputs and flows out via its outputs. You can update input properties using property bindings. And you can subscribe to output properties using event bindings.

Property Bindings

Say we have a component that renders a Todo. We could use this component in our template as follows:

This tells Angular that whenever myTodo changes, Angular needs to automatically update the todo component by calling the model setter with a new todo.

Event Bindings

Now, let’s make the component a bit more interesting and add an event.

This tells Angular that if an event called “complete” is fired, it should invoke onCompletingTodo.

Now, let’s look at TodoCmp itself.

The component declares that is has an input property named “model” and an output property “complete”. Only the input properties of a component can be updated using property bindings. This separates the input of the component from its internal state.

Angular uses the Rx style of programming to deal with events. EventEmitter is an implementation of both the observable and observer interfaces (see here). So we can use it to fire events, and Angular can use it to listen to events.

As you can see, the core syntax of property and event bindings is very simple. On top of the core syntax, Angular provides some syntax sugar to make expressing common programming patterns easier. It is important to understand that this is just sugar, and it does not change the semantics.

Two-Way Bindings

Two-way data bindings are convenient in certain scenarios, most notably for handling input. As I have mentioned, property bindings are used to pass data from the parent to the child, and event bindings are used to pass data from the child to the parent. So we can use the two to implement two-way bindings.

Although this works, this is too verbose. And since this is such a common pattern, Angular provides syntax sugar to remove the boilerplate.

We refer to the [()] brackets are “banana in a box”. Why is it called this way? It’s an accident. While working on this feature I was reading the CS paper “Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire”, in which the authors refer to one type of brackets as banana brackets. So I looked at [()] and thought “hey, this looks like a banana too, a banana in box!”.

To complete this example, let’s implement NgModel in Angular 2.

This is an extremely naive implementation of NgModel, but it shows how to implement the two-way data-binding behavior: the input will be updated when the text changes, and the text field will be updated when the input changes.

Note that in opposite to Angular 1, you can tell which bindings are “two-way” and which are “one-way” just by looking at the template. Also, since only one direction, property bindings, are executed automatically by Angular, the two-way behavior is a lot more predictable. It does not break any of the guarantees that Angular 2 provides: this is just some syntax sugar, nothing else.

Also, don’t get scared! You won’t have to implement NgModel. Angular 2 comes with a robust form-handling module, which includes an implementation of NgModel.

Interpolation

is just sugar for

Passing Constants

is just sugar for

Removing Brackets

Although this is hardly can be called “sugar”, you can replace all the brackets in your template with bind-, on-, and bindon-.

is the same as

Let’s Recap

  • Input and output properties are the public API of a directive.
  • Data flows into a directive via input properties.
  • Data flows out of a directive via output properties.
  • You can update input properties using property bindings.
  • You can subscribe to output properties using event bindings.
  • You can use property and event bindings to implement two-way bindings.
  • Angular provides syntax sugar for two-way bindings, interpolation, and passing constants.

References

It is not uncommon to have two components that have to talk to each other. To enable that Angular 2 supports defining references in the template.

When there is a component on the element, the variable refers to the component instance. When there is no component on the element, the variable refers to the element itself.

Syntax Sugar

is equivalent to

Templates and *

Angular treats template elements in a special way. They are used to create views, chunks of DOM you can dynamically manipulate. The * syntax is a shortcut that lets you void writing the whole <template> element. Let me show you how it works.

Say we render a list of todo components.

This de-sugars it into

which de-sugars into

The ngFor directive that creates the view exports the $implicit and index variables, which we bind to in the template. All the variables declared on a template element are available only inside the element. That is why the following is incorrect:

It is important to understand what the * syntax expands into when you build your own directives that manipulate views. For instance, if you look at NgFor, you will see that it has the ngForOf property, but does not have the of property.

Why don’t just have custom syntax for ngFor like Angular 1 does? There are a few good reasons. Having custom syntax means that you have to know this micro language to use the directive. It also means that tools (e.g., IDEs and linters) cannot understand your template and cannot provide autocompletion and refactoring.

Web Components and Native Elements

Everything I talked about in this blog post (local variables, property and event bindings) works exactly the same way for web components and standard html elements.

I can replace TodoCmp with a web component and still interact with it the same way.

I can replace the video player with a web component and still interact with it the same way.

This is extremely important as more and more component libraries get available. It is also important when running on native (which is one of the Angular 2 goals). It would really suck if you had to wrap every native component into an Angular 2 component. Angular 2 allows you to use any native component directly, using the same syntax, and wrap them into Angular components only when you, for example, need to use dependency injection.

Design Goals

I hope you got an idea of how the template syntax works in Angular 2. Now, I want to talk about why does it work this way? What were the design goals?

Our main design goal was to make templates more explicit, so the developer can understand and refactor the template without knowing what directives are used there, and how they work.

Regardless of what the component element is, you know that name in [property1]=”name” is a field read and name in property2=“name”` is a string literal. You also know that the name property cannot be updated by the component: property bindings update from the parent to the child.

Here, we can see that name can be updated because we use the [()] syntax.

Similarly, you can tell what variables are defined in the template by just looking at *ngFor.

Second, we wanted to enable rich tooling. In the following example tools can statically deduce that the first index is a field on the component, and the second index is a local variable exported by ngFor.

This is just one example of how analyzable Angular 2 templates are. And since editors and IDEs can analyze templates statically, they can provide autocompletion and refactoring. WebStorm 2016 already does it. And we are working on improving the Angular 2 support in VS Code, Sublime Text, Atom, and others.

Finally, we want to make integration with native components and web components seamless. This means that Angular cannot special case certain events (e.g., ngClick) and instead has to provide generic mechanisms to update any property or listen to any event.

Victor Savkin is a co-founder of Nrwl — Enterprise Angular Consulting.

If you liked this, click the💚 below so other people will see this here on Medium. Follow @victorsavkin to read more about Angular.

--

--

Nrwlio co-founder, Xoogler, Xangular. Work on dev tools for TS/JS. @NxDevTools and Nx Cloud architect. Calligraphy and philosophy enthusiast. Stoic.