angular-cn/public/docs/ts/latest/tutorial/toh-pt3.jade

175 lines
9.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

include ../../../../_includes/_util-fns
:marked
Our app is growing.
Use cases are flowing in for reusing components, passing data to components, and creating more reusable assets. Let's separate the heroes list from the hero details and make the details component reusable.
[Run the live example for part 3](/resources/live-examples/toh-3/ts/plnkr.html)
.l-main-section
:marked
## Where We Left Off
Before we continue with our Tour of Heroes, lets verify we have the following structure. If not, well need to go back and follow the previous chapters.
.filetree
.file angular2-tour-of-heroes
.children
.file node_modules
.file app
.children
.file app.component.ts
.file boot.ts
.file index.html
.file package.json
.file tsconfig.json
:marked
### Keep the app transpiling and running
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
code-example(format="." language="bash").
npm run go
:marked
This will keep the application running while we continue to build the Tour of Heroes.
## Making a Hero Detail Component
Our heroes list and our hero details are all in the same component. What if we want to reuse the hero details somewhere else in our app? This would be difficult since it is intermixed with the heroes list. Lets make this easier and separate the hero details into its own component to make this more reusable.
### Separating the Hero Detail Component
Well need a new file and a new component to host our hero details. Lets create a new file named `hero-detail.component.ts` in the `app` folder, and create a component named `HeroDetailComponent`.
+makeExample('toh-3/ts-snippets/hero-detail.component.pt3.ts', 'hero-detail-component-1', 'hero-detail.component.ts (HeroDetailComponent)')
:marked
We want to use `HeroDetailComponent` from our original `AppComponent`. Well need the selector name when we refer to it in `AppComponent`s template. We export the `HeroDetailComponent` here so we can later import it into our `AppComponent`, which well do after we finish creating our `HeroDetailComponent`.
We anticipate our template will contain multiple lines. So lets initialize the `template` property to an empty string between back-ticks.
+makeExample('toh-3/ts-snippets/hero-detail.component.pt3.ts', 'hero-detail-component-2', 'hero-detail.component.ts (Empty template)')
:marked
Remember, we want to refer to our `HeroDetailComponent` in the `AppComponent`. This is why we export the `HeroDetailComponent` class.
#### Hero Detail Template
Our heroes and hero details are combined in one template in `AppComponent` so we need to separate them. Lets move the appropriate template content from `AppComponent` and paste it in the template property of `HeroDetailComponent`.
Lets also change the name of the property in the template from `selectedHero` to `hero`, as it is more appropriate for a reusable component.
+makeExample('toh-3/ts-snippets/hero-detail.component.pt3.ts', 'hero-detail-component-3', 'hero-detail.component.ts (Detail template)')
:marked
Now our hero detail template exists only in our `HeroDetailComponent`.
#### Importing
Now that we have the foundation for the component, we need to make sure that we import everything we are using in the component. Lets add the following import statement to the top of our `hero-detail.component.ts` file to get the exports from Angular that we are using.
+makeExample('toh-3/ts-snippets/hero-detail.component.pt3.ts', 'imports-1', 'hero-detail.component.ts (Importing Component)')
:marked
#### Declaring our Hero
Our `HeroDetailComponent`s template refers to a hero, so lets add a property on the component to hold the hero.
+makeExample('toh-3/ts-snippets/hero-detail.component.pt3.ts', 'hero-property', 'hero-detail.component.ts (Hero property)')
:marked
Uh oh. We declare the `hero` property as being of type `Hero` but our `Hero` interface is over in the `app.component.ts` file. We now have two components, each in their own file, that need to reference the `Hero` interface. Lets solve this problem by removing the `Hero` interface from `app.component.ts` and moving it to its own file named `hero.ts`.
+makeExample('toh-3/ts/app/hero.ts', 'hero-interface', 'hero.ts (Exported Hero interface)')
:marked
We export the `Hero` interface from `hero.ts` because we will need to import it in both of our component files. Lets add the following import statement to the top of both `app.component.ts` and `hero.-detail.component.ts`.
+makeExample('toh-3/ts/app/app.component.ts', 'hero-import', 'hero-detail.component.ts and app.component.ts (Import the Hero interface)')
:marked
Now we can also use the `Hero` interface from other files by importing it.
#### Defining the Input for HeroDetailComponent
Our `HeroDetailComponent` needs to be told what hero to use. We have a `hero` property, but we need a way for the `AppComponent` to tell the `HeroDetailComponent` the hero it should use.
Lets declare the inputs for our component in the `@Component` decorators `inputs` property. We will set the input to the `hero` property so it matches the `hero` property on the `HeroDetailComponent`.
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'inputs', 'hero-detail.component.ts (Component input)')
:marked
Now our `AppComponent`, or any component that refers to `HeroDetailComponent`, can tell the `HeroDetailComponent` which hero to use.
### Making AppComponent Refer to the HeroDetailComponent
Our `HeroDetailComponent` is ready, but we need to go back to the `AppComponent` and clean up some loose ends.
First we need to tell our `AppComponent` about our new component. Lets add an import statement so we can refer to the `HeroDetailComponent`.
+makeExample('toh-3/ts/app/app.component.ts', 'hero-detail-import', 'app.component.ts (Importing HeroDetailComponent)')
:marked
Lets find the location of the template content we removed from `AppComponent` and refer to our new component.
+makeExample('toh-3/ts-snippets/app.component.pt3.html', 'component-1', 'app.component.ts (Using HeroDetailComponent)')
:marked
This would be good enough if the component did not have any inputs. But we do, so we want to pass the selected hero to the `hero` input of the `HeroDetailComponent`, as shown below:
+makeExample('toh-3/ts-snippets/app.component.pt3.html', 'component-2', 'app.component.ts (Passing the hero to HeroDetailComponent)')
:marked
### Declaring HeroDetailComponent
We've imported `HeroDetailComponent`, we've used it in the template, but we haven't told our `AppComponent` that we intend to use it in the template. We must declare our intention to use `HeroDetailComponent` in `AppComponent`.
Let's add the `directives` property to our `@Component` decorator and set it to an array which contains the `HeroDetailComponent`. We'll do this after our `template` and `styles` properties in the `@Component` decorator.
+makeExample('toh-3/ts/app/app.component.ts', 'declaring', 'app.component.ts (Declaring HeroDetailComponent)')
:marked
Our `AppComponent`s template should now look like this
+makeExample('toh-3/ts/app/app.component.ts', 'hero-detail-template', 'app.component.ts (Template)')
.l-sub-section
:marked
Naming conventions can be useful.
We want to identify which files are components. Our `AppComponent` is named `app.component.ts` and our `HeroDetailComponent` is `hero-detail.component.ts`. We follow this consistent pattern which makes it easy to know what is in each file, by following a naming convention where we identify which files contain a component.
:marked
<!-- TODO
.l-sub-section
:marked
Learn more about naming conventions in the chapter [Naming Conventions]
:marked
-->
:marked
### Checking Our Work
When we view our app in the browser we see the list of heroes. When we select a hero we can see the selected heros details. If we want to show hero details somewhere else in our app we can use the `HeroDetailComponent` and pass in a hero.
Weve created our first reusable component!
### Reviewing the App Structure
Lets verify that we have the following structure after all of our good refactoring in this chapter:
.filetree
.file angular2-tour-of-heroes
.children
.file node_modules
.file app
.children
.file app.component.ts
.file boot.ts
.file hero.ts
.file hero-detail.component.ts
.file index.html
.file package.json
.file tsconfig.json
.l-main-section
:marked
## The Road Weve Travelled
Lets take stock in what weve built.
* We created a reusable component
* We learned how to make a component accept input
[Run the live example for part 3](/resources/live-examples/toh-3/ts/plnkr.html)
### The Road Ahead
Our Tour of Heroes has become more reusable using shared components.
We want to create reusable services that retrieve our data. As our app evolves,
well learn how to design it to make it easier to grow and maintain.
Well learn more about these tasks in the coming chapters.