Used as a building block
Using a component as a building block means it will be part of another component's template. Essentially, it will be seen as that component's child. This line of thinking is quite natural and means that we can think of our application as a hierarchical tree of components. A component in Angular consists of a controller class and a template as we have mentioned previously. A typical component looks like so:
// an example component
@Component({
selector: 'example-component'
})
export class ExampleComponent {}
The @Component decorator function adds metadata to the class. This instructs Angular on how to create the component so that Angular can place the component in the DOM. This enables you to use it as a responder to a route or as your own custom element. The property selector is what decides what your component should be called, if used as a custom element. Example usage looks like the following:
// an example container component
@Component({
selector: `
{{ title }}
<example-component>
`
})
export class ContainerComponent {
title ="container component";
}
The fact that components can be used this way makes it easy to think about an app as consisting of a hierarchical tree of components. A Todo application could therefore look like the following:
AppComponent
TodoList
TodoItem
TodoItem
TodoItem
...
Let's start to create this app, starting with the AppComponent. As this is the topmost component, it is also referred to as the root component. The AppComponent should render the TodoListComponent in its own template, like so:
// mvc/MvcExample/src/app/app.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-root",
template: `
<todo-list></todo-list>
`,
styleUrls: ["./app.component.css"]
})
export class AppComponent {
title = "app";
}
The next step is defining the TodoListComponent and knowing that it should be able to render a number of TodoItemComponent instances within its template. The size of a list is usually unknown. This is exactly what the structural directive *ngFor is for. So that is what we will utilize in the following code as we define the TodoListComponent:
// mvc/MvcExample/src/app/todo-list.component.ts
import { Component } from "@angular/core";
@Component({
selector: "todo-list",
template: `
<h1>{{title}}</h1> <custom></custom>
<div *ngFor="let todo of todos">
<todo-item [todo]="todo" ></todo-item>
</div>
` . // the view
})
export class TodoListComponent { // the controller class
title: string;
todos = [{
title: "todo1"
},{
title: "todo1"
}]
}
Here, we can see that we render out a list of todo items by looping out the todos array in the template, like so:
<div *ngFor="let todo of todos">
<todo-item [todo]="todo" ></todo-item>
</div>
We can see in the preceding code that we are rendering out the todo-item selector, which points to a TodoItemComponent that we are yet to define. Worth noting is how we pass it a todo object and assign it to an input property on the TodoItemComponent. The definition for said component is as follows:
// mvc/MvcExample/src/app/todo-item.component.ts
import { Component, Input } from "@angular/core";
@Component({
selector: "todo-item",
template: `<h1>{{todo.title}}</h1>`
})
export class TodoItemComponent {
@Input() todo;
}
Reasoning about which components should exist as part of which other components is something you are going to dedicate a lot of time to.