In this article, we’ll take a look a bit closer at Angular 2 components — how they’re defined, and how to get data into them and back out of them.
This is the second part in the Angular 2 series. You can read part one here. We covered the basic idea of components and decorators in an earlier article, and have specifically seen the
@View decorators used to build an Angular application. This article dives in a bit deeper. However, we can’t cover everything about components in a single article, so future articles will take up other aspects of Angular 2 components.
As we’ve covered in an earlier article, Angular 2 components are the key building block for Angular applications. They include a view, defined with HTML and CSS, and an associated controller that implements functionality needed by the view. The controller has three major responsibilities:
- Manage the model, i.e. the application data used by the view
- Implement methods needed by the view for things like submitting data or hiding/showing sections of the UI
- Managing data related to the state of the view, such as which item in a list is currently selected.
Depending on your background, the above list might sound familiar. In fact, the Angular component controller sounds very much like the original definition of a view model as defined by John Gossman in 2005:
The term means “Model of a View”, and can be thought of as abstraction of the view, but it also provides a specialization of the Model that the View can use for data-binding. In this latter role the ViewModel contains data-transformers that convert Model types into View types, and it contains Commands the View can use to interact with the Model. — Source (captured 11/27/2015)
@Component decorator we saw in the first article in this series.
The above describes an individual component, but Angular 2 applications are actually made up of a hierarchy of components – they begin with a root component that contains as descendants all the components used in the application. Angular 2 components are intended to be self-contained, because we want to encapsulate our component functions and we don’t want other code to arbitrarily reach into our components to read or change properties. Also, we don’t want our component to affect another component written by someone else. An obvious example is CSS: if we set CSS for one component, we don’t want our CSS to “bleed out” to another components just as we don’t want other CSS to “bleed in” to our component.
At the same time, components do need to exchange data. Angular 2 components can receive data from their parent as long as the receiving component has specifically said it’s willing to receive data. Similarly, components can send data to their parents by trigger an event the parent listens for. Let’s look at how the component hierarchy behaves. To begin, we can draw it as follows:
Each box is a component and technically this representation is called “graph” — a data structure consisting of nodes and connecting “edges.” The arrows represent the data flow from one component to another, and we can see that data flows in only one direction — from the top downwards to descendants. Also, note there are no paths that allow you to travel from one node, through other nodes and back to the one where you started. The official name for this kind of data structure is a “directed acyclic graph” — that is, it flows in only one direction and has no circular paths in it.
This kind of structure has some important features: it’s predictable, it’s simple to traverse, and it’s easy to see what’s impacted when a change is made. For Angular’s purposes, when data changes in one node, it’s easy to find the downstream nodes that could be affected.