UPDATE (18th May 2017): This tutorial has been updated to the latest version of Angular (Angular 4). Note that the Angular team has re-branded the terms Angular 2 to Angular and Angular 1.x to AngularJS which are now the official names of these frameworks.
Good morning! Time for some Angular 2 goodness! Yesterday you learned about Angular 2 Routing and today you are going to learn about how you can create forms and validate them in Angular 2.
UPDATE (13th October 2017): This Angular 2 tutorial has been updated to the latest version of Angular (Angular 4). Note that the Angular team has re-branded the terms Angular 2 to Angular and Angular 1.x to AngularJS which are now the official names of these frameworks.
UPDATE (11th October 2017): This Angular 2 tutorial has been updated to the latest version of Angular (Angular 4). Note that the Angular team has re-branded the terms Angular 2 to Angular and Angular 1.x to AngularJS which are now the official names of these frameworks.
In this article you are going to create your second component and you are going to get a better understanding of the different possibilities Angular 2 offers in terms of data bindings. Let’s get to it!
The Code Samples
You can download the code samples for this article in this GitHub repository. You can also check the unbelievably cool online editor Stackblitz which has awesome support for writing Angular prototypes on the web. My recommendation is that you follow the tutorial along using your own development environment, that way you get to enjoy the full Angular developer experience. But if you don’t have time or energy to set it up right now, then try Stackblitz.
A Person Details Component
We are interested in learning more information about these Star Wars characters. That’s why we are going to update our application so that when you click on a person within the PeopleListComponent we show a more detailed information for the person we have selected.
We are going to start by showing that detail information directly within the PeopleListComponent and then we are going to extract it into its very own PersonDetailsComponent.
The final solution should look something like this:
Our People List Component Right Now
This is how the PeopleListComponent looked like at the end of the last exercise:
import{ Component, OnInit }from'@angular/core'import{ Person }from'../person'import{ PeopleService }from'../people.service'@Component({
selector:'app-people-list',
template:`
<!-- this is the new syntax for ng-repeat -->
<ul>
<li *ngFor="let person of people">
{{person.name}}
</li>
</ul>
`,
styleUrls:['./people-list.component.scss'],})exportclassPeopleListComponentimplementsOnInit{
people: Person[]constructor(private peopleService: PeopleService){}ngOnInit(){this.people =this.peopleService.getAll()}}
We are retrieving a list of Star Wars characters for our PeopleService and showing them to our users. We achieve that by taking advantage of the *ngFor directive and the interpolation binding.
Showing Person Details When Clicking on a Character
Now we want to be able to select a person whenever we click on it. How do we do that? We use the Angular 2 (click) event binding.
@Component({
selector:'app-people-list',
template:`
<!-- this is the new syntax for ng-repeat -->
<ul>
<li *ngFor="let person of people">
<!-- HERE: add a element with click event binding -->
<a href="#" (click)="selectPerson(person)">
{{person.name}}
</a>
</li>
</ul>
`})
The (click)="selectPerson(person)"event binding tells Angular 2 to call the selectPerson component method whenever a user clicks on the a element.
We can now update our PeopleListComponent to provide that method to the view:
exportclassPeopleListComponentimplementsOnInit{
people: Person[]=[]
selectedPerson: Person
constructor(private _peopleService: PeopleService){}ngOnInit(){this.people =this._peopleService.getAll()}// HERE is the new methodselectPerson(person){this.selectedPerson = person
}}
So now, whenever a user clicks on a person in the list, Angular 2 will call the selectPerson method that will in turn update the selectedPerson property within the PeopleListComponent.
If we now use that selectedPerson property in the template we get to the solution we were looking for:
@Component({
selector:'app-people-list',
template:`
<!-- this is the new syntax for ng-repeat -->
<ul>
<li *ngFor="let person of people">
<a href="#" (click)="selectPerson(person)">
{{person.name}}
</a>
</li>
</ul>
<!-- HERE: we add the template for the person details -->
<section *ngIf="selectedPerson">
<h2>You selected: {{selectedPerson.name}}</h2>
<h3>Description</h3>
<p>
{{selectedPerson.name}} weights {{selectedPerson.weight}} and is {{selectedPerson.height}} tall.
</p>
</section>
`})
Notice how we used the *ngIf binding (like ng-if in AngularJS) another structural directive like *ngFor that manipulates the DOM based on an expression. In this case, it shows the person detail information only when a person has been selected.
The completed PeopleListComponent with the person details looks like this:
import{ Component, OnInit }from'@angular/core'import{ Person }from'../person'import{ PeopleService }from'../people.service'@Component({
selector:'app-people-list',
template:`
<!-- this is the new syntax for ng-repeat -->
<ul>
<li *ngFor="let person of people">
<a href="#" (click)="selectPerson(person)">
{{person.name}}
</a>
</li>
</ul>
<section *ngIf="selectedPerson">
<h2>You selected: {{selectedPerson.name}}</h2>
<h3>Description</h3>
<p>
{{selectedPerson.name}} weights {{selectedPerson.weight}} and is {{selectedPerson.height}} tall.
</p>
</section>
`,})exportclassPeopleListComponentimplementsOnInit{
people: Person[]=[]
selectedPerson: Person
constructor(private peopleService: PeopleService){}ngOnInit(){this.people =this.peopleService.getAll()}selectPerson(person: Person){this.selectedPerson = person
}}
What Are Angular 2 Event Bindings?
Angular 2 data binding works a little bit different than it did in AngularJS.
Angular 2 offers a wide variety of binding options. You’ve seen the interpolation binding that provides a one way data binding from the component to the template to display data. And now you’ve learned about the event binding that provides a one way data binding between the template and the underlying component.
The event binding syntax lets you bind component methods directly to DOM events. You no longer need to have custom Angular bindings like we had in AngularJS with ng-click, ng-change, etc… you just bind to (click), (change) or whichever event that you desire.
Extracting Person Details Into Its Own Component
If you look at the previous code sample for PeopleComponentList it feels like there’s too much going on in there. When you start having a nagging feeling of theres-too-much-going-on-here is the perfect signal that you need to start thinking about breaking things down.
A person’s details are a perfect candidate for having its own component. Let’s create a PersonDetailsComponent! Yey!
We start creating a new person-details.component.ts file and module to contain our new component. Again the Angular CLI comes to the rescue, type the following to generate the new component:
PS> ng g c -it -is person-details
# ng generate component --inline-template --inline-style
This will include the piece of the template related to displaying person details information:
import{ Component, OnInit }from'@angular/core'import{ Person }from'../person'@Component({
selector:'app-person-details',
template:`
<!-- we moved the details template here -->
<section *ngIf="person">
<h2>You selected: {{person.name}}</h2>
<h3>Description</h3>
<p>
{{person.name}} weights {{person.weight}} and is {{person.height}} tall.
</p>
</section>
`,
styles:[],})exportclassPersonDetailsComponentimplementsOnInit{
person: Person
constructor(){}ngOnInit(){}}
There it is. So now we have a component that represents person details and that we can reuse and compose with other components in our application. Yippi! But how can we send in data so that person property gets some person to display? Or in other words, how can we bind a person to this component?
We use the Angular 2 Input decorator:
// include this on top of person-details.component.tsimport{ Component, Input }from'@angular/core'exportclassPersonDetailsComponent{// update PersonDetailsComponent// to decorate the person property with @Input()@Input() person: Person
}
This will mark the person property as an input to the PersonDetailsComponent and will allow other components to send a person into the component. How? By using Angular 2 property bindings like this:
Indeed, we can update the PeopleListComponent to make use of the new component. Remember, we normally need to start by adding the new component to app.module.ts so our application will be aware of it. Since we are used the Angular CLI, it should’ve taken care of this plumbing for us. If you check app.module.ts you should be able to see that the following bits of code have been already added. First the import declaration:
Then the component is included within the declarations property of the NgModule decorator:
@NgModule({
declarations:[
AppComponent,
PeopleListComponent,
PersonDetailsComponent,// Here is our new component!],
imports:[BrowserModule, FormsModule, HttpModule],
providers:[PeopleService],
bootstrap:[AppComponent],})exportclassAppModule{}
The next step is to use our brand new component within the template of PeopleListComponent:
<!-- this is the new syntax for ng-repeat --><ul><li*ngFor="let person of people"><ahref="#"(click)="selectPerson(person)">
{{person.name}}
</a></li></ul><app-person-details[person]="selectedPerson"></app-person-details>
The complete PeopleListComponent looks like this:
import{ Component, OnInit }from'@angular/core'import{ Person }from'../person'import{ PeopleService }from'../people.service'@Component({
selector:'app-people-list',
template:`
<!-- this is the new syntax for ng-repeat -->
<ul>
<li *ngFor="let person of people">
<a href="#" (click)="selectPerson(person)">
{{person.name}}
</a>
</li>
</ul>
<app-person-details [person]="selectedPerson"></app-person-details>
`,
styleUrls:['./people-list.component.scss'],})exportclassPeopleListComponentimplementsOnInit{
selectedPerson: Person
people: Person[]constructor(private peopleService: PeopleService){}ngOnInit(){this.people =this.peopleService.getAll()}selectPerson(person: Person){this.selectedPerson = person
}}
And you are done! If you check your browser right now (remember ng serve --open or ng s -o to start the web server and load your app in the browser) you should be able to test that whenever you click on a Star Wars person its details are shown. Good job!
What are Angular 2 Property Bindings?
Angular 2 property bindings are like the reverse to event bindings as they provide a one-way data binding between your component and your template.
They allow you to bind to custom properties when communicating between components just like you saw in this exercise but they also let you bind to native DOM properties like the src of an image element. Property bindings are yet another example of a way that Angular 2 does away with a lot of custom directives from AngularJS: there’s no need for the ng-src directive when you can just bind directly to [src].
Want to Learn more about Angular 2 Data Bindings?
Later in this series I will write an article looking more closely at the Angular 2 data binding system, but if you are curious right now, here are a couple of articles that will tell you more about how Angular 2 Data Binding works:
Angular 2 Basics: Template Syntax describes the basics of Angular 2 template syntax including interpolation, event and property bindings.
The Angular 2 Cheatsheet has a nice compilation of different useful bindings that you can use.
Great job! You have already created two Angular 2 components, learned a lot about Angular 2 template syntax with interpolation, event bindings, property bindings, *ngFor, *ngIf, you have created your first service and injected using Angular 2 DI. Think about all the stuff that you’re going to build with Angular 2!! :)
UPDATE (10th October 2017): This Angular 2 tutorial has been updated to the latest version of Angular (Angular 4). Note that the Angular team has re-branded the terms Angular 2 to Angular and Angular 1.x to AngularJS which are now the official names of these frameworks.
Ok! So you’ve learned how to get started with an Angular 2 and TypeScript application and you’ve written your first component. Yey! The next thing you are going to learn about are services and dependency injection.
In the previous example we had a PeopleListComponent where we initialized an array of Star Wars persons of note. But your component shouldn’t know or care about where the list of people is coming from be it local storage, a database, a web service or the grace of the holy spirit.
That’s why we are going to extract that data access logic into a service that we’ll inject into our component through its constructor. Breaking your application in smaller pieces that have a single responsibility will make it much easier to reason about, more maintainable, reusable and testable. Win Win!
Earlier this week Lisa Ryrholm and I were at the ngStockholm meetup helping people get started with Angular. We’re going to have yet another workshop next week and I thought to myself… Wouldn’t it be nice if the people coming to the workshop could have a detailed reference about each and one of the exercises in the workshop? Wouldn’t it be cool if this reference had nice explanations and step by step directions that they could use during the workshop or refer back to later on? Something in a neat tutorial format? Of course!
And voilà! Here it is! Are you interested in a step by step introduction to Angular? Then let’s get started coding!