The Core Concepts of Angular 2
In this blog post I will talk about the three core concepts of Angular 2: components, dependency injection, and bindings.
Let's Build an App
Let's say we want to build this application, which is a list of tech talks that you can filter, watch, and rate.
To build an Angular 2 application you define a set of components, for every UI element, screen, and route. An application will always have a root component that contains all other components. In other words, every Angular 2 application will have a component tree, which for this application may look like this:
Application is the root component. The Filters component has the speaker input and the filter button. TalkList is the list you see at the bottom. And TalkCmp is an item in that list.
To understand what constitutes a component in Angular 2, let's look closer at TalkCmp.
Input and Output Properties
A component has input and output properties, which can be defined in the component decorator or using property decorators.
Data flows into a component via input properties. Data flows out of a component via output properties.
Input and output properties are the public API of a component. You use them when you instantiate a component in your application.
You can set input properties using property bindings, through square brackets. You can subscribe to output properties using event bindings, through parenthesis.
A component has a template, which describes how the component is rendered on the page.
Angular needs to know two things to render the template: the list of directives that can be used in its template, and the template itself. You can define the template externally, using the templateUrl, as in the example above, or inline.
Components have a well-defined lifecycle, which you can tap into. The TalkCmp component does not subscribe to any lifecycle events, but some other components can. For instance, this component will be notified when its input properties change.
A component can contain a list of providers the component and its children may inject.
In this example, we have the backend and the logger services declared in the root component, which makes them available in the whole application. The talks component injects the backend service. I will talk about dependency injection in detail in the second part of this article. For now, just remember that components configures dependency injection.
To turn an Angular component into something rendered in the DOM you have to associate an Angular component with a DOM element. We call such elements host elements.
A component can interact with its host DOM element in the following ways:
- It can listen to its events.
- It can update its properties.
- It can invoke methods on it.
The component, for instance, listens to the input event using hostListeners, trims the value, and then stores it in a field. Angular will sync up the stored value with the DOM.
Note, I don't actually interact with the DOM directly. Angular 2 aims to provide a higher-level API, so the native platform, the DOM, will just reflect the state of the Angular application.
This is useful for a couple of reasons:
- It makes components easier to refactor.
- It allows unit testing most of the behavior of an application without touching the DOM. Such tests are easier to write and understand. In addition, they are significantly faster.
- It allows running Angular applications in a web worker.
- It allows running Angular applications outside of the browser completely, on other platforms, for instance using NativeScript.
Sometimes you just need to interact with the DOM directly. Angular 2 provides such APIs, but our hope is that you will rarely need to use them.
Components are Self-Describing
What I have listed constitutes a component.
- A component knows how to interact with its host element.
- A component knows how to render itself.
- A component configures dependency injection.
- A component has a well-defined public API of input and output properties.
All of these make components in Angular 2 self-describing, so they contain all the information needed to instantiate them. This is extremely important.
This means that any component can be bootstrapped as an application. It does not have to be special in any way. Moreover, any component can be loaded into a router outlet. As a result, you can write a component that can be bootstrapped as an application, loaded as a route, or used in some other component directly. This results in less API to learn. And it also makes components more reusable.
What About Directives?
If you are familiar with Angular 1, you must be wondering "What happened to directives?".
Actually directives are still here in Angular 2. The component is just the most important type of a directive, but not the only one. A component is a directive with a template. But you can still write decorator-style directives, which do not have templates.
Components are fundamental building blocks of Angular 2 applications.
- They have well-defined inputs and outputs.
- They have well-defined lifecycle.
- They are self-describing.