Compare commits
1 Commits
master
...
revert-279
Author | SHA1 | Date | |
---|---|---|---|
![]() |
138dd66707 |
@ -1,173 +0,0 @@
|
||||
# Create a feature component
|
||||
|
||||
At the moment, the `HeroesComponent` displays both the list of heroes and the selected hero's details.
|
||||
|
||||
Keeping all features in one component as the application grows will not be maintainable.
|
||||
You'll want to split up large components into smaller sub-components, each focused on a specific task or workflow.
|
||||
|
||||
In this page, you'll take the first step in that direction by moving the hero details into a separate, reusable `HeroDetailComponent`.
|
||||
|
||||
The `HeroesComponent` will only present the list of heroes.
|
||||
The `HeroDetailComponent` will present details of a selected hero.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
For the sample app that this page describes, see the <live-example></live-example>.
|
||||
|
||||
</div>
|
||||
|
||||
## Make the `HeroDetailComponent`
|
||||
|
||||
Use the Angular CLI to generate a new component named `hero-detail`.
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate component hero-detail
|
||||
</code-example>
|
||||
|
||||
The command scaffolds the following:
|
||||
|
||||
* Creates a directory `src/app/hero-detail`.
|
||||
|
||||
Inside that directory four files are generated:
|
||||
|
||||
* A CSS file for the component styles.
|
||||
* An HTML file for the component template.
|
||||
* A TypeScript file with a component class named `HeroDetailComponent`.
|
||||
* A test file for the `HeroDetailComponent` class.
|
||||
|
||||
The command also adds the `HeroDetailComponent` as a declaration in the `@NgModule` decorator of the `src/app/app.module.ts` file.
|
||||
|
||||
|
||||
### Write the template
|
||||
|
||||
Cut the HTML for the hero detail from the bottom of the `HeroesComponent` template and paste it over the generated boilerplate in the `HeroDetailComponent` template.
|
||||
|
||||
The pasted HTML refers to a `selectedHero`.
|
||||
The new `HeroDetailComponent` can present _any_ hero, not just a selected hero.
|
||||
So replace "selectedHero" with "hero" everywhere in the template.
|
||||
|
||||
When you're done, the `HeroDetailComponent` template should look like this:
|
||||
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.html" header="src/app/hero-detail/hero-detail.component.html"></code-example>
|
||||
|
||||
### Add the `@Input()` hero property
|
||||
|
||||
The `HeroDetailComponent` template binds to the component's `hero` property
|
||||
which is of type `Hero`.
|
||||
|
||||
Open the `HeroDetailComponent` class file and import the `Hero` symbol.
|
||||
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts"
|
||||
region="import-hero" header="src/app/hero-detail/hero-detail.component.ts (import Hero)">
|
||||
</code-example>
|
||||
|
||||
The `hero` property
|
||||
[must be an _Input_ property](guide/inputs-outputs "Input and Output properties"),
|
||||
annotated with the `@Input()` decorator,
|
||||
because the _external_ `HeroesComponent` [will bind to it](#heroes-component-template) like this.
|
||||
|
||||
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding">
|
||||
</code-example>
|
||||
|
||||
Amend the `@angular/core` import statement to include the `Input` symbol.
|
||||
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="import-input" header="src/app/hero-detail/hero-detail.component.ts (import Input)"></code-example>
|
||||
|
||||
Add a `hero` property, preceded by the `@Input()` decorator.
|
||||
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" header="src/app/hero-detail/hero-detail.component.ts" region="input-hero"></code-example>
|
||||
|
||||
That's the only change you should make to the `HeroDetailComponent` class.
|
||||
There are no more properties. There's no presentation logic.
|
||||
This component simply receives a hero object through its `hero` property and displays it.
|
||||
|
||||
## Show the `HeroDetailComponent`
|
||||
|
||||
The `HeroesComponent` is still a master/detail view.
|
||||
|
||||
It used to display the hero details on its own, before you cut that portion of the template. Now it will delegate to the `HeroDetailComponent`.
|
||||
|
||||
The two components will have a parent/child relationship.
|
||||
The parent `HeroesComponent` will control the child `HeroDetailComponent`
|
||||
by sending it a new hero to display whenever
|
||||
the user selects a hero from the list.
|
||||
|
||||
You won't change the `HeroesComponent` _class_ but you will change its _template_.
|
||||
|
||||
{@a heroes-component-template}
|
||||
|
||||
### Update the `HeroesComponent` template
|
||||
|
||||
The `HeroDetailComponent` selector is `'app-hero-detail'`.
|
||||
Add an `<app-hero-detail>` element near the bottom of the `HeroesComponent` template, where the hero detail view used to be.
|
||||
|
||||
Bind the `HeroesComponent.selectedHero` to the element's `hero` property like this.
|
||||
|
||||
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding" header="heroes.component.html (HeroDetail binding)">
|
||||
|
||||
</code-example>
|
||||
|
||||
`[hero]="selectedHero"` is an Angular [property binding](guide/property-binding).
|
||||
|
||||
It's a _one way_ data binding from
|
||||
the `selectedHero` property of the `HeroesComponent` to the `hero` property of the target element, which maps to the `hero` property of the `HeroDetailComponent`.
|
||||
|
||||
Now when the user clicks a hero in the list, the `selectedHero` changes.
|
||||
When the `selectedHero` changes, the _property binding_ updates `hero`
|
||||
and the `HeroDetailComponent` displays the new hero.
|
||||
|
||||
The revised `HeroesComponent` template should look like this:
|
||||
|
||||
<code-example path="toh-pt3/src/app/heroes/heroes.component.html"
|
||||
header="heroes.component.html"></code-example>
|
||||
|
||||
The browser refreshes and the app starts working again as it did before.
|
||||
|
||||
## What changed?
|
||||
|
||||
As [before](tutorial/toh-pt2), whenever a user clicks on a hero name,
|
||||
the hero detail appears below the hero list.
|
||||
Now the `HeroDetailComponent` is presenting those details instead of the `HeroesComponent`.
|
||||
|
||||
Refactoring the original `HeroesComponent` into two components yields benefits, both now and in the future:
|
||||
|
||||
1. You simplified the `HeroesComponent` by reducing its responsibilities.
|
||||
|
||||
1. You can evolve the `HeroDetailComponent` into a rich hero editor
|
||||
without touching the parent `HeroesComponent`.
|
||||
|
||||
1. You can evolve the `HeroesComponent` without touching the hero detail view.
|
||||
|
||||
1. You can re-use the `HeroDetailComponent` in the template of some future component.
|
||||
|
||||
## Final code review
|
||||
|
||||
Here are the code files discussed on this page.
|
||||
|
||||
<code-tabs>
|
||||
|
||||
<code-pane header="src/app/hero-detail/hero-detail.component.ts" path="toh-pt3/src/app/hero-detail/hero-detail.component.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/hero-detail/hero-detail.component.html" path="toh-pt3/src/app/hero-detail/hero-detail.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/heroes/heroes.component.html" path="toh-pt3/src/app/heroes/heroes.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/app.module.ts" path="toh-pt3/src/app/app.module.ts">
|
||||
</code-pane>
|
||||
|
||||
</code-tabs>
|
||||
|
||||
## Summary
|
||||
|
||||
* You created a separate, reusable `HeroDetailComponent`.
|
||||
|
||||
|
||||
* You used a [property binding](guide/property-binding) to give the parent `HeroesComponent` control over the child `HeroDetailComponent`.
|
||||
|
||||
|
||||
* You used the [`@Input` decorator](guide/inputs-outputs)
|
||||
to make the `hero` property available for binding
|
||||
by the external `HeroesComponent`.
|
@ -1,140 +1,148 @@
|
||||
# Crear un componente de características
|
||||
# Create a feature component
|
||||
|
||||
Por el momento, el `HeroesComponent` muestra tanto la lista de héroes como los detalles de los héroes seleccionados.
|
||||
At the moment, the `HeroesComponent` displays both the list of heroes and the selected hero's details.
|
||||
|
||||
Mantener toda la funcionalidad en un componente se vuelve menos sostenible a medida que la aplicación crece.
|
||||
Deberá dividir un componente grande en subcomponentes más pequeños que se centren en una tarea o flujo de trabajo en particular.
|
||||
Keeping all features in one component as the application grows will not be maintainable.
|
||||
You'll want to split up large components into smaller sub-components, each focused on a specific task or workflow.
|
||||
|
||||
Esta página da el primer paso en ese camino moviendo los detalles del héroe a otro `HeroDetailComponent` reutilizable.
|
||||
In this page, you'll take the first step in that direction by moving the hero details into a separate, reusable `HeroDetailComponent`.
|
||||
|
||||
`HeroesComponent` solo muestra una lista de héroes.
|
||||
`HeroDetailComponent` muestra los detalles del héroe seleccionado.
|
||||
The `HeroesComponent` will only present the list of heroes.
|
||||
The `HeroDetailComponent` will present details of a selected hero.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
Para ver la aplicación de ejemplo que describe esta página, consulte el <live-example></live-example>.
|
||||
|
||||
For the sample app that this page describes, see the <live-example></live-example>.
|
||||
|
||||
</div>
|
||||
|
||||
## Crear `HeroDetailComponent`
|
||||
## Make the `HeroDetailComponent`
|
||||
|
||||
Usa el CLI de Angular para generar un nuevo componente llamado `hero-detail`.
|
||||
Use the Angular CLI to generate a new component named `hero-detail`.
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate component hero-detail
|
||||
</code-example>
|
||||
|
||||
Este comando generará una plantilla para el archivo `HeroDetailComponent` y declarará este componente en el `AppModule`.
|
||||
Este comando produce la siguiente plantilla:
|
||||
The command scaffolds the following:
|
||||
|
||||
* Crear el directorio `src/app/hero-detail`
|
||||
* Creates a directory `src/app/hero-detail`.
|
||||
|
||||
Genera cuatro archivos en este directorio:
|
||||
Inside that directory four files are generated:
|
||||
|
||||
* Archivo CSS para estilo de componente
|
||||
* Archivo HTML para la plantilla el componente
|
||||
* Archivo TypeScript de la clase de componente denominada `HeroDetailComponent`
|
||||
* Archivo de prueba de la clase `HeroDetailComponent`
|
||||
* A CSS file for the component styles.
|
||||
* An HTML file for the component template.
|
||||
* A TypeScript file with a component class named `HeroDetailComponent`.
|
||||
* A test file for the `HeroDetailComponent` class.
|
||||
|
||||
Este comando también agrega `HeroDetailComponent` como `declaraciones` en el decorador `@ NgModule` del archivo `src/app/app.module.ts`.
|
||||
The command also adds the `HeroDetailComponent` as a declaration in the `@NgModule` decorator of the `src/app/app.module.ts` file.
|
||||
|
||||
### Escribir plantilla
|
||||
|
||||
Corta el HTML de detalles del héroe desde la parte inferior de la plantilla `HeroesComponent` y pégalo en la plantilla generada en las plantilla `HeroDetailComponent`.
|
||||
### Write the template
|
||||
|
||||
Las referencias HTML pegadas `selectedHero`.
|
||||
El nuevo `HeroDetailComponent` puede mostrar _cualquier_héroe, no solo el héroe seleccionado.
|
||||
Por lo tanto, reemplaza todos los "selectedHero" en la plantilla con "hero".
|
||||
Cut the HTML for the hero detail from the bottom of the `HeroesComponent` template and paste it over the generated boilerplate in the `HeroDetailComponent` template.
|
||||
|
||||
Cuando termines, las plantilla `HeroDetailComponent` deberían verse así:
|
||||
The pasted HTML refers to a `selectedHero`.
|
||||
The new `HeroDetailComponent` can present _any_ hero, not just a selected hero.
|
||||
So replace "selectedHero" with "hero" everywhere in the template.
|
||||
|
||||
When you're done, the `HeroDetailComponent` template should look like this:
|
||||
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.html" header="src/app/hero-detail/hero-detail.component.html"></code-example>
|
||||
|
||||
### Añadir la propiedad `@Input()` al héroe
|
||||
### Add the `@Input()` hero property
|
||||
|
||||
Las plantillas `HeroDetailComponent` están vinculadas a la propiedad `hero` de un componente que es del tipo `Hero`.
|
||||
The `HeroDetailComponent` template binds to the component's `hero` property
|
||||
which is of type `Hero`.
|
||||
|
||||
Abre el archivo de clase `HeroDetailComponent` e importe el símbolo `Hero`.
|
||||
Open the `HeroDetailComponent` class file and import the `Hero` symbol.
|
||||
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts"
|
||||
region="import-hero" header="src/app/hero-detail/hero-detail.component.ts (import Hero)">
|
||||
</code-example>
|
||||
|
||||
La propiedad `hero` debe ser una [_propiedad de entrada_](guide/template-syntax#inputs-outputs " Input and Output properties"), anotada con el decorador `@Input()` porque el `HeroesComponent` _externo_ [se vinculará de esta manera.](#heroes-component-template)
|
||||
The `hero` property
|
||||
[must be an _Input_ property](guide/inputs-outputs "Input and Output properties"),
|
||||
annotated with the `@Input()` decorator,
|
||||
because the _external_ `HeroesComponent` [will bind to it](#heroes-component-template) like this.
|
||||
|
||||
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding">
|
||||
</code-example>
|
||||
|
||||
Modifique la declaración de importación `@angular/core` para incluir el símbolo `Input`.
|
||||
Amend the `@angular/core` import statement to include the `Input` symbol.
|
||||
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="import-input" header="src/app/hero-detail/hero-detail.component.ts (import Input)"></code-example>
|
||||
|
||||
Agrega la propiedad `hero` antepuesta por el decorador `@Input()`.
|
||||
Add a `hero` property, preceded by the `@Input()` decorator.
|
||||
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" header="src/app/hero-detail/hero-detail.component.ts" region="input-hero"></code-example>
|
||||
|
||||
Este es el único cambio que debe realizar en la clase `HeroDetailComponent`.
|
||||
No se requieren más propiedades o lógica de visualización.
|
||||
Este componente solo toma un objeto héroe a través de la propiedad `hero` y lo muestra.
|
||||
That's the only change you should make to the `HeroDetailComponent` class.
|
||||
There are no more properties. There's no presentation logic.
|
||||
This component simply receives a hero object through its `hero` property and displays it.
|
||||
|
||||
## Mostrar `HeroDetailComponent`
|
||||
## Show the `HeroDetailComponent`
|
||||
|
||||
El `HeroesComponent` todavía está en la vista maestra/detalle.
|
||||
The `HeroesComponent` is still a master/detail view.
|
||||
|
||||
Hasta que eliminé los detalles del héroe de Plantillas, lo estaba mostrando en este componente. Ahora deleguemos a `HeroDetailComponent`.
|
||||
It used to display the hero details on its own, before you cut that portion of the template. Now it will delegate to the `HeroDetailComponent`.
|
||||
|
||||
Los dos componentes tienen una relación padre-hijo.
|
||||
Para mostrar un nuevo héroe cada vez que el usuario selecciona un héroe de la lista,
|
||||
El padre `HeroesComponent` controla al hijo `HeroDetailComponent` enviándolo.
|
||||
The two components will have a parent/child relationship.
|
||||
The parent `HeroesComponent` will control the child `HeroDetailComponent`
|
||||
by sending it a new hero to display whenever
|
||||
the user selects a hero from the list.
|
||||
|
||||
No cambiarás la _clase_ de `HeroesComponent` pero cambiarás su _template_.
|
||||
You won't change the `HeroesComponent` _class_ but you will change its _template_.
|
||||
|
||||
{@a heroes-component-template}
|
||||
|
||||
### Actualizar las plantillas `HeroesComponent`
|
||||
### Update the `HeroesComponent` template
|
||||
|
||||
El selector para `HeroDetailComponent` es `'app-hero-detail'`.
|
||||
The `HeroDetailComponent` selector is `'app-hero-detail'`.
|
||||
Add an `<app-hero-detail>` element near the bottom of the `HeroesComponent` template, where the hero detail view used to be.
|
||||
|
||||
Agrega un elemento `<app-hero-detail>` a la parte inferior de las plantillas `HeroesComponent` donde la vista detallada de héroe existió una vez.
|
||||
|
||||
Vincula `HeroesComponent.selectedHero` a la propiedad `hero` de este elemento de la siguiente manera:
|
||||
Bind the `HeroesComponent.selectedHero` to the element's `hero` property like this.
|
||||
|
||||
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding" header="heroes.component.html (HeroDetail binding)">
|
||||
|
||||
</code-example>
|
||||
|
||||
`[hero]="selectedHero"` es el [enlace de propiedad](guide/template-syntax#property-binding). de Angular
|
||||
`[hero]="selectedHero"` is an Angular [property binding](guide/property-binding).
|
||||
|
||||
Este es un enlace de datos unidireccional de la propiedad `selectedHero` `HeroesComponent` a la propiedad `hero` del elemento objetivo.
|
||||
Aquí se asigna la propiedad `hero` de `HeroDetailComponent`.
|
||||
It's a _one way_ data binding from
|
||||
the `selectedHero` property of the `HeroesComponent` to the `hero` property of the target element, which maps to the `hero` property of the `HeroDetailComponent`.
|
||||
|
||||
Cuando el usuario hace clic en un héroe en la lista, el `selectedHero` cambia.
|
||||
Cuando `selectedHero` cambia,el _enlace de propiedad_ actualiza `hero` y
|
||||
`HeroDetailComponent` muestra el nuevo héroe.
|
||||
Now when the user clicks a hero in the list, the `selectedHero` changes.
|
||||
When the `selectedHero` changes, the _property binding_ updates `hero`
|
||||
and the `HeroDetailComponent` displays the new hero.
|
||||
|
||||
La plantilla modificada de `HeroesComponent` se ve así:
|
||||
The revised `HeroesComponent` template should look like this:
|
||||
|
||||
<code-example path="toh-pt3/src/app/heroes/heroes.component.html"
|
||||
header="heroes.component.html"></code-example>
|
||||
|
||||
Una vez que se actualiza el navegador, la aplicación comenzará a funcionar nuevamente como antes.
|
||||
The browser refreshes and the app starts working again as it did before.
|
||||
|
||||
## ¿Que ha cambiado?
|
||||
## What changed?
|
||||
|
||||
[Como antes](tutorial/toh-pt2), cada vez que un usuario hace clic en el nombre de un héroe, el detalle del héroe aparece debajo de la lista de héroes. Ahora HeroDetailComponent presenta esos detalles en lugar de HeroesComponent.
|
||||
As [before](tutorial/toh-pt2), whenever a user clicks on a hero name,
|
||||
the hero detail appears below the hero list.
|
||||
Now the `HeroDetailComponent` is presenting those details instead of the `HeroesComponent`.
|
||||
|
||||
Refactorizar el `HeroesComponent` original en dos componentes te beneficiará ahora y en el futuro.
|
||||
Refactoring the original `HeroesComponent` into two components yields benefits, both now and in the future:
|
||||
|
||||
1. Simplificado `HeroesComponent` al reducir su responsabilidad.
|
||||
1. You simplified the `HeroesComponent` by reducing its responsibilities.
|
||||
|
||||
1. Puedes convertir un `HeroDetailComponent` en un editor enriquecido de héroes sin tocar el padre `HeroesComponent` principal.
|
||||
1. You can evolve the `HeroDetailComponent` into a rich hero editor
|
||||
without touching the parent `HeroesComponent`.
|
||||
|
||||
1. Puedes evolucionar `HeroesComponent` sin tocar la vista de detalles del héroe.
|
||||
1. You can evolve the `HeroesComponent` without touching the hero detail view.
|
||||
|
||||
1. Puedes reutilizar `HeroDetailComponent` en futuros componentes de Plantillas.
|
||||
1. You can re-use the `HeroDetailComponent` in the template of some future component.
|
||||
|
||||
## Revisión final del código
|
||||
## Final code review
|
||||
|
||||
Los archivos de código descritos en esta página son:
|
||||
Here are the code files discussed on this page.
|
||||
|
||||
<code-tabs>
|
||||
|
||||
@ -152,10 +160,14 @@ Los archivos de código descritos en esta página son:
|
||||
|
||||
</code-tabs>
|
||||
|
||||
## Resumen
|
||||
## Summary
|
||||
|
||||
* Creaste un `HeroDetailComponent` independiente y reutilizable.
|
||||
* You created a separate, reusable `HeroDetailComponent`.
|
||||
|
||||
* Usaste el [enlace de propiedad](guide/template-syntax#property-binding) para que el padre `HeroesComponent` pueda controlar al hijo `HeroDetailComponent`.
|
||||
|
||||
* Usaste el [`decorador @Input`](guide/template-syntax#inputs-outputs) para hacer que la propiedad del heroe esté disponible para ser vinculada por el componente `HeroesComponent` externamente.
|
||||
* You used a [property binding](guide/property-binding) to give the parent `HeroesComponent` control over the child `HeroDetailComponent`.
|
||||
|
||||
|
||||
* You used the [`@Input` decorator](guide/inputs-outputs)
|
||||
to make the `hero` property available for binding
|
||||
by the external `HeroesComponent`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user