AppComponent is doing everything at the moment.
In the beginning, it showed details of a single hero.
Then it became a master/detail form with both a list of heroes and the hero detail.
Soon there will be new requirements and capabilities.
You can't keep piling features on top of features in one component; that's not maintainable.
You'll ned to break it up into sub-components, each focused on a specific task or workflow.
AppComponent could become a simple shell that hosts those sub-components.
In this page, you'll take the first step in that direction by carving out the hero details into a separate, reusable component.
When you're done, the app should look like this
Where you left off
Before getting started on this page, verify that you have the following structure from earlier in the Tour of Heroes. If not, go back to the previous pages.
Keep the app transpiling and running while you build the Tour of Heroes
by entering the
npm start command in a terminal window
as you did before.
Make a hero detail component
Add a file named
hero-detail.component.ts to the
This file will hold the new
The file and component names follow the standard described in the Angular style guide.
The component class name should be written in upper camel case and end in the word "Component". The hero detail component class is
The component file name should be spelled in lower dash case, each word separated by dashes, and end in
HeroDetailComponentclass goes in the
Start writing the
HeroDetailComponent as follows:
To define a component, you always import the
@Component decorator provides the Angular metadata for the component.
The CSS selector name,
hero-detail, will match the element tag
that identifies this component within a parent component's template.
Near the end of this tutorial page,
you'll add a
<hero-detail> element to the
export the component class because you'll always
import it elsewhere.
Hero detail template
To move the hero detail view to the
cut the hero detail content from the bottom of the
and paste it into a new
template property in the
HeroDetailComponent has a hero, not a selected hero.
Replace the word, "selectedHero", with the word, "hero", everywhere in the template.
When you're done, the new template should look like this:
Add the hero property
HeroDetailComponent template binds to the component's
Add that property to the
HeroDetailComponent class like this:
hero property is typed as an instance of
Hero class is still in the
Now there are two components that need to reference the
The Angular style guide recommends one class per file anyway.
Hero class from
app.component.ts to its own
Now that the
Hero class is in its own file, the
AppComponent and the
HeroDetailComponent have to import it.
Add the following
import statement near the top of both the
app.component.ts and the
The hero property is an input property
Later in this page,
AppComponent will tell the child
HeroDetailComponent which hero to display
by binding its
selectedHero to the
hero property of the
The binding will look like this:
Putting square brackets around the
hero property, to the left of the equal sign (=),
makes it the target of a property binding expression.
You must declare a target binding property to be an input property.
Otherwise, Angular rejects the binding and throws an error.
First, amend the
@angular/core import statement to include the
Then declare that
hero is an input property by
preceding it with the
@Input decorator that you imported earlier.
Read more about input properties in the Attribute Directives page.
That's it. The
hero property is the only thing in the
All it does is receive a hero object through its
hero input property and then bind to that property with its template.
Here's the complete
Declare HeroDetailComponent in the AppModule
Every component must be declared in one—and only one—Angular module.
app.module.ts in your editor and import the
HeroDetailComponent so you can refer to it.
HeroDetailComponent to the module's
In general, the
declarations array contains a list of application components, pipes, and directives that belong to the module.
A component must be declared in a module before other components can reference it.
This module declares only the two application components,
Read more about Angular modules in the NgModules guide.
Add the HeroDetailComponent to the AppComponent
AppComponent is still a master/detail view.
It used to display the hero details on its own, before you cut out that portion of the template.
Now it will delegate to the
hero-detail is the CSS
That's the tag name of the element that represents the
<hero-detail> element near the bottom of the
where the hero detail view used to be.
Coordinate the master
AppComponent with the
by binding the
selectedHero property of the
hero property of the
Now every time the
selectedHero changes, the
HeroDetailComponent gets a new hero to display.
AppComponent template should look like this:
As before, whenever a user clicks on a hero name,
the hero detail appears below the hero list.
But now the
HeroDetailView is presenting those details.
Refactoring the original
AppComponent into two components yields benefits, both now and in the future:
You simplified the
AppComponentby reducing its responsibilities.
You can evolve the
HeroDetailComponentinto a rich hero editor without touching the parent
You can evolve the
AppComponentwithout touching the hero detail view.
You can re-use the
HeroDetailComponentin the template of some future parent component.
Review the app structure
Verify that you have the following structure:
Here are the code files discussed in this page.
The road you’ve travelled
Here's what you achieved in this page:
- You created a reusable component.
- You learned how to make a component accept input.
- You learned to declare the required application directives in an Angular module. You
listed the directives in the
- You learned to bind a parent component to a child component.
Your app should look like this
The road ahead
The Tour of Heroes app is more reusable with shared components,
but its (mock) data is still hard coded within the
That's not sustainable.
Data access should be refactored to a separate service
and shared among the components that need data.
You’ll learn to create services in the next tutorial page.