import {Component} from '@angular/core';
@Component({
selector: 'root', template: `
<article>
<feedback></feedback>
</article>
` })
export class RootComponent {}
Note
You'll notice that the like count value being passed to the child component as an input has been removed. Very simply, that convention will not work anymore, as binding it here would draw the like count from RootComponent, which does not have this information.
Correcting data binding
The FeedbackComponent will need to retrieve the like count directly:
[app/feedback.component.ts]
import {Component, Inject, forwardRef} from '@angular/core';
import {ArticleComponent} from './article.component';
@Component({
selector: 'feedback', template: `
<h1>Number of likes: {{ val }}</h1>
<button (click)="likeArticle()"
[disabled]="!likeEnabled">
Like this article!
</button>
` })
export class FeedbackComponent { private val:number;
private likeEnabled:boolean = false;
private articleComponent:ArticleComponent;
constructor(@Inject(forwardRef(() => ArticleComponent)) articleComponent:ArticleComponent) {
this.articleComponent = articleComponent;
this.updateLikes();
}
updateLikes() {
this.val = this.articleComponent.likes;
}
likeArticle():void {
this.articleComponent.incrementLikes();
this.updateLikes();
}
setLikeEnabled(newEnabledStatus:boolean):void { this.likeEnabled = newEnabledStatus;
} }
That's it! The application should behave identically to the setup from the Getting ready section of the recipe.
How it works...
ContentChild does nearly the same thing as ViewChild; it just looks in a different place.
ContentChild directs Angular to find the first instance of FeedbackComponent present inside the ArticleComponent tags. Here, this step refers to anything that is interpolated by <ng-content>. It then assigns the found component instance to the decorated class member. The reference is updated along with any view updates. This decorated member will refer to the child component instance and can be interacted with like any normal object instance.
There's more...
Since Angular performs hierarchical rendering, ContentChild will not be ready until the view is initialized, but rather, after the AfterContentInit life cycle hook. This can be demonstrated as follows:
[app/article.component.ts]
import {Component, ContentChild, ngAfterContentInit}
from '@angular/core';
import {FeedbackComponent} from './feedback.component';
@Component({
selector: 'article', template: `
<input type="checkbox"
(click)="changeLikesEnabled($event)">
<ng-content></ng-content>
` })
export class ArticleComponent implements AfterContentInit { @ContentChild(FeedbackComponent)
feedbackComponent:FeedbackComponent;
likes:number = 0;
constructor() {
console.log(this.feedbackComponent);
}
ngAfterContentInit() {
console.log(this.feedbackComponent);
}
incrementLikes():void { this.likes++;
}
changeLikesEnabled(e:Event):void {
this.feedbackComponent.setLikeEnabled(e.target.checked);
} }
This will first log undefined inside the constructor as the content, and
therefore FeedbackComponent does not yet exist. Once the AfterContentInit life cycle hook occurs, you will be able to see FeedbackComponent logged to the console.
ContentChildren
If you would like to get a reference to multiple components, you can perform an identical
reference acquisition process using ContentChildren, which will provide you with QueryList
of all the matching components inside the component's tags.
Tip
A QueryList can be used like an array with its toArray() method. It also exposes a changes property, which emits an event every time a member of QueryList changes.
See also
Utilizing component lifecycle hooks gives an example of how you can integrate with Angular 2's component rendering flow.
Referencing a parent component from a child component describes how a component can gain a direct reference to its parent via injection.
Configuring mutual parent-child awareness with ViewChild and forwardRef instructs you on how to properly use ViewChild to reference child component object instances.
Chapter 3. Building Template-Driven and Reactive Forms
This chapter will cover the following recipes:
Implementing simple two-way data binding with ngModel Implementing basic field validation with a FormControl Bundling FormControls with a FormGroup
Bundling FormControls with a FormArray Implementing basic forms with ngForm
Implementing basic forms with FormBuilder and formControlName Creating and using a custom validator
Creating and using a custom asynchronous validator with Promises
Introduction
Forms are important elemental constructs for nearly every web application, and they have been reimagined for the better in Angular 2. Angular 1 forms were very useful, but they were totally dependent on the conventions of ngModel. Angular 2's newfound conventions remove it from
ngModel dependence and offer a fresh approach to form and information management that ultimately feels cleaner and more approachable.
Fundamentally, it is important to understand where and why forms are useful. There are many places in an application where multitudinous input demands association, and forms are certainly useful in this context. Angular 2 forms are best used when validating the said input, especially so when multiple-field and cross-field validation is required. Additionally, Angular forms maintain the state of various form elements, allowing the user to reason the "history" of an input field.
It is also critical to remember that the Angular 2 form behavior, much in the same way as its event and data binding, is getting integrated with the already robust browser form behavior. Browsers are already very capable of submitting data, recalling data upon a page reload, simple validation, and other behaviors that pretty much all forms rely upon. Angular 2 doesn't redefine these; rather, it integrates with these behaviors in order to link in other behaviors and data that are part of either a framework or your application.
Tip
In this chapter, be aware of the duality of the use of FormsModule and ReactiveFormsModule. They behave very differently and are almost always used separately when it comes to form construction.