5. Separated components

(single responsibility principle)

Our template become more and more extensive, it has more details in it. It shows all heroes and in the same moment it presents details for one hero, too. Such component is difficult to maintain as with more features it will become more complicated.
In this chapter, we will separate this component to be easier to maintain. The list of heroes will stay in this component. For the part that presents hero's details, we will create a new component named HeroDetailComponent.

Create the HeroDetailComponent

We are already familiar with ng generate component command. Into the terminal write the following command:

ng generate component hero-detail

It generates the new component and automatically adds reference of the HeroDetailComponent to the AppModule.

Edit the new template

We will move the details of the heroes into the new component template. Here it is possible to reuse this component without such selected hero. We will replace the "selectedHero" with "hero". Open the hero-detail.component.html file and type the changes. It should look like this:

<div *ngIf="hero">
    <h2>{{ hero.name | uppercase }} Details</h2>
    <div>
        <span>id: </span>{{hero.id}}</div>
    <div>
        <label>name:
            <jqxInput [(ngModel)]="hero.name" [placeHolder]="'hero name'"></jqxInput>
        </label>
    </div>
</div>

Import data throw the template attribute via @Input

The hero property that we include in our template will be of type Hero. This means we should import the Hero class.

import { Hero } from '../hero';

Now we need to add the Input directive to that component. With the @Input() decorator we will get the external data and we need to include it into the imported Component and OnInit decorators:

import { Component, OnInit, Input } from '@angular/core';

The HeroesComponent template will translate data by the hero property, like this: <app-hero-detail [hero]="selectedHero"></app-hero-detail>

The HeroesComponent's template now looks like this:

<h2>My Heroes</h2>
<jqxGrid #grid
    (onRowclick)="rowdetails($event)"
    [autoheight]="true" 
    [theme]="'material'">
        <tr>  
            <th>Id</th>  
            <th>Name</th>  
        </tr>  
        <tr *ngFor="let hero of heroes">  
        <td>  
                {{hero.id}}</td> 
        <td>  
                {{hero.name}}</td>  
        </tr>  
</jqxGrid>

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

The syntax to determine a property that will be used in the template is @Input() and after that the name of the property hero. In our case:

@Input() hero: Hero;

That is all we do in this component - get the data (hero property) and represent it on the display. With the <app-hero-detail [hero]="selectedHero"></app-hero-detail> we simplify the structure in the HeroesComponent. After these changes, when you save all files, it will reflect in our example and it should work normally as before.

Benefits from this refactoring

Everything looks like before but now our components have the following benefits:

  1. Reducing the responsibilities of the HeroesComponent and simplified it as a result of this.
  2. You can change or absolutely transform the HeroDetailComponent into a new editor without touching the HeroesComponent.
  3. The changes on the HeroesComponent do not need to care about these changes into the "hero details" view.
  4. You can use the HeroDetailComponent into another place where you want.

In conclusion