Angular 2 architecture quickstart: components, inputs, and services
This is a guide for developers with experience creating applications in other frameworks, who are new to Angular 2 and trying to get a sense of its architectural patterns. We’re going to focus on components and how they communicate with the rest of the application. There are other ways of doing these things; this is my opinion of the best ones given my current understanding.
Components
These are the building blocks of an application: self-contained systems typically including a controller (the component’s class) and a view specified by a template.
A component is typically included by other parent components by referencing its selector in the parent template.
@Component({
selector: 'product'
})<!-- inside some other component's template: -->
<product></product>
Two-way binding is provided by Angular for public properties of the controller.
export class ProductComponent {
public name: string;
}<!--
when the input's value changes, the component's name property is updated, and vice versa, via 2-way binding
-->
<input ([ngModel])="name" />
Inputs and Outputs
These are one way in which components communicate with each other. Because inputs and outputs couple components explicitly, they are best used when a child component would never exist outside this particular context — composition rather than aggregation, in classical OOP terms.
Inputs are exposed as component properties, and also as a stream of change events.
export class ProductComponent implements OnChanges {
@Input isFeatured: boolean;
ngOnChanges(changes: SimpleChanges) {
// receives a stream of changes to any inputs, e.g. when
// localValueOfFeatured changes in the parent (see below)
}
}<product [isFeatured]="localValueOfFeatured"></product>
Outputs are exposed to the parent via an event stream.
@Component({
template: `<button (click)="like()">Like</button>`
})
export class ProductComponent {
@Output onLike = new EventEmitter<boolean>();
like() {
this.onLike.emit(true);
}
}<product (onLike)="handleLikesInParentComponent($event)"></product>
Services
This is the other way to move data in and out of components. More generally though, services are modular objects injectable magically by Angular on demand. They can communicate with other services injected into them, as well as publishing their own data streams. Perhaps the most common example is the Http service, which allows us to make an outgoing web services request.
In the context of inter-component communication, services are the better choice over inputs and outputs when the source or destination of a data stream is nonessential to the component. Each component depends on the service responsible for this line of communication, rather than on each other.
@Component({
template: `<button (click)="like()">Like</button>`
})
export class ProductComponent {
private product: Product; // a model object
// request injection of the service
constructor (private productLikeService: ProductLikeService) {}
like() {
this.productLikeService.publish(this.product);
}
}export class ProductLikeService {
this.subject = new Subject<Product>();
subscribe() {
return this.subject.asObservable();
}
publish(product: Product) {
// any consumers of this service will receive the product
this.subject.next(product);
}
}
