barbarian meets coding

WebDev, UX & a Pinch of Fantasy

Getting Started With Angular 2 Step by Step: 3 - Your Second Component and Angular 2 Data Binding

| Comments

UPDATE (11th May 2016): 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.

This is the third article on the Getting Started with Angular 2 Step by Step series if you missed the previous articles go and check them out!

Good morning! In the last two parts of this series you wrote your first Angular 2 component, you refactored your data access logic into a service and injected into your component taking advantage of Angular 2 dependency injection.

Angular 2 Getting Started

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.

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:

Angular 2 Step By Step Result Exercise 3

Our People List Component Right Now

This is how the PeopleListComponent looked like at the end of the last exercise:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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']
})
export class PeopleListComponent implements OnInit {
  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 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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export class PeopleListComponent implements OnInit{
  people: Person[] = [];
  selectedPerson: Person;

  constructor(private _peopleService : PeopleService){ }

  ngOnInit(){
    this.people = this._peopleService.getAll();
  }

  <!-- HERE is the new method -->
  selectPerson(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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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>
  `
})
export class PeopleListComponent implements OnInit{
  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:

1
2
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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: []
})
export class PersonDetailsComponent implements OnInit {
  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:

1
2
3
4
5
6
7
8
// include this on top of person-details.component.ts
import { Component, Input } from '@angular/core';

export class PersonDetailsComponent {
  // 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:

1
<app-person-details [person]="selectedPerson"></app-person-details>

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:

1
import { PersonDetailsComponent } from './person-details/person-details.component';

Then the component is included within the declarations property of the NgModule decorator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@NgModule({
  declarations: [
    AppComponent,
    PeopleListComponent,
    PersonDetailsComponent // Here is our new component!
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [PeopleService],
  bootstrap: [AppComponent]
})
export class AppModule { }

The next step is to use our brand new component within the template of PeopleListComponent:

1
2
3
4
5
6
7
8
9
<!-- 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>

The complete PeopleListComponent looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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']
})
export class PeopleListComponent implements OnInit {
  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:

Concluding

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!! :)

Up next! Routing! I think… (checking GitHub)… Routing!!

Have a great day!

Comments