Although the Router part of Angular is still changing a lot, the public API for building components is already quite stable. In this post we will go through on how we can build components with this new version of Angular, based on some code examples.

In this post we will learn the essentials of how to build Angular components, but a bit also on how not to build them:

  • Angular - where to start?
  • Components - the component public API
  • Internals of Components - the Controller
  • Properties and how bindings work
  • Do's and dont's of Properties
  • Events
  • Do's and dont's of Events
  • Conclusions

Where to start - Browser components

Let's start by looking into how browser components work, taking for example the browser native component select:

This component like all browser components has some interesting properties:

  • we don't need to be aware of its internal structure in order to be able to reason about the component. We only need to know its public API.

  • we don't need to look at other parts of the application to know what this component is doing and how it will behave

Angular allows us to build UI components that are in every way similar to native browser components: encapsulated, reusable, and easy to reason about.

The Angular component API in a nutshell

This is an example of an Angular component: a dropdown component, similar to the select native component but for example with support for disabled elements and other extra features:

Here is what is going on here:

  • this component has an input property options, via which we provide a list of countries. Properties are the input that a component receives, and we use them to pass in an input model into the component. Based on the model the view will be built accordingly.

  • the component emits an output event named selection when a new option is selected. Events are the output that a component produces. They report to the outside world a relevant change of the component internal state.

The internal structure of a component

Every component has two main internal parts:

  • An internal Html/CSS tree that encapsulates how the component view is built
  • a Controller class, which coordinates the interaction between the view and the input model

Given this, let's now go through the 2 main component concepts (properties and events) with examples.

Understanding Properties

Let's start with properties, and for that let's introduce the color-me component, which can be used like this:

And here is what the component looks live:

Angular color-me component

As we can see the color-me component is just an input box where we can type the name of a color and see it painted in a sample square.

How properties work

The component looks like a native browser component, with the exception of the [sampleColor] notation. This means that the string
blue is passed as an input property to the component.

The input property will be automatically bound to a controller property, so we can use it inside the component.

The Component Controller

This is how the controller of the color-me component is implemented:

As we can see, the sampleColor input property is bound to the controller, and renamed to color. This property is generally available inside the controller via this.color. It's used for example to start up the view with an initial color.

The component View

This is how the component view is internally implemented in
color-me.html:

A bit more is going on here:

  • a local variable input is defined using #input

  • The input property value of the input box is being filled in with the color name via [value]="color"

  • The background CSS property is binded to the value of the input box via [style.background]="input.value"

So here we see that properties are not only a mechanism for passing data inside a component. They can be generally used to write to any valid DOM element property, such as for example the property input.value, which contains the input text field value, or style.background which contains the color of the sample rectangle.

When is the color applied

In this case, the color is applied as the user types into the input box. This only happens because there is an event listener hooked inside the component on the keyup event, which causes change detection to be triggered when the user types.

Try to remove the empty (keyup) listener, and the color will no longer be applied.

How NOT to use properties

Properties are meant to pass input data to a component, that preferably might change over time.Properties should be avoided in these cases:

  • when passing constant string values to the component, such as for example [width]="100px". For that, use the Attribute annotation instead.

  • when trying to pass a command to the component, instructing the component to trigger a given action. This is to be avoided because it creates a tight coupling between the caller of the command and the component itself. Ideally, the component should only receive input data and react to it. The provider of the data should have no information of how the data gets rendered or which actions it triggers.

Events

The second main concept of the component API is Events. Let's start by introducing the scroll-me component:

And here is how the component looks like:

Angular scroll-me component

The component just scrolls a list up and down, when the corresponding buttons are clicked. This is the template of the component, and we can see the click event being bound on the down button with the (click)="expression" syntax:

Again in this example, we are binding directly to a DOM property via the [scroll-top] binding. This binding allows us to write directly to the Javascript scrollTop property of the selection div, which is another example of how Angular encourages the direct use of the DOM API.

But did you see it it? the Up button does not have a (click) binding, but the component still works! Let's take a look at the controller code to see what is going on:

We can see that in the constructor of the component an event listener is being manually added to the up button. There is nothing special about that code, it's just the pure DOM API event subscription API.

The angular syntax for binding events via (click) is mainly an abbreviated way to do the same as this code.

How does the event get detected then?

The event gets detected via the Angular change detection mechanism, which runs at the end of each virtual machine turn. This mechanism is based on the notion of Zones, see this previous post for more about it, or have a look at this video that describes how Events really work and how they relate to Zones:

Do's and dont's of Events

The event mechanism is easier to misuse than the properties mechanism. With properties, we really have to go out of our way to pass in a command object of some sort to trigger an action inside the object.

With events, it's very easy to fall into the situation of using an event to trigger an action in an external component. The key thing to bear in mind about events, is that in order to keep the event emitter decoupled from the subscriber, the emitter should only report about changes on its internal state: for example, a selection occurred in a dropdown component.

This way the emitting component stays decoupled from the event subscribers and does not have any information on what the event is being used for.

Conclusions

The Angular API is much simpler to learn and use correctly than the Angular 1 API: there are a lot less concepts and they are much simpler to reason about.

The components are better isolated and if the notions of properties and events are well applied, it's simpler to write truly reusable components that can be understood just by looking at an HTML template.

To start trying out the Angular component API, you can find all the running code from this post here, or clone the angular2-seed repository to start with a clean and ready to use project.

If you want to learn more about Angular, have a look at the Angular for Beginners Course:

If you enjoyed this post, here some other popular posts on our blog: