Compare commits
10 Commits
revert-279
...
guide/libr
Author | SHA1 | Date | |
---|---|---|---|
5d8f869913 | |||
2ca7ee8f54 | |||
ebee38994f | |||
6ebb0246ab | |||
f8c56ec8eb | |||
c7a054fa31 | |||
6ff6acbb21 | |||
8a09cb9794 | |||
eeb59b4f4d | |||
7afbc3a1c1 |
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,12 +1,12 @@
|
||||
## Lista de Verificación del PR
|
||||
Comprueba si tu PR cumple los siguientes requisitos:
|
||||
|
||||
- [ ] El mensaje de commit esta conforme con [nuestras reglas](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit)
|
||||
- [ ] El mensaje de commit esta conforme con [nuestras reglas](https://github.com/angular-hispano/angular/blob/master/CONTRIBUTING.md#-formato-para-el-mensaje-de-los-commits)
|
||||
- [ ] Probe los cambios que agregué (arreglo de bugs / funcionalidades)
|
||||
- [ ] Revisé previamente las traducciones o cambios de contenido
|
||||
- [ ] Consulté el [diccionario de términos](https://github.com/angular-hispano/angular/blob/master/aio/diccionario-de-términos.md) en español
|
||||
- [ ] He creado dos archivos con la extensión correspondiente(.en.md para el archivo en inglés y .md para el Archivo en español)
|
||||
- [ ] La PR fue enlazada con el issue correspondiente
|
||||
- [ ] He enlazado el commit con el issue correspondiente <!-- ejemplo Fixes #X -->
|
||||
|
||||
|
||||
## Tipo de PR
|
||||
|
37
aio/content/guide/libraries.en.md
Normal file
37
aio/content/guide/libraries.en.md
Normal file
@ -0,0 +1,37 @@
|
||||
# Overview of Angular libraries
|
||||
|
||||
Many applications need to solve the same general problems, such as presenting a unified user interface, presenting data, and allowing data entry.
|
||||
Developers can create general solutions for particular domains that can be adapted for re-use in different apps.
|
||||
Such a solution can be built as Angular *libraries* and these libraries can be published and shared as *npm packages*.
|
||||
|
||||
An Angular library is an Angular [project](guide/glossary#project) that differs from an app in that it cannot run on its own.
|
||||
A library must be imported and used in an app.
|
||||
|
||||
Libraries extend Angular's base functionality. For example, to add [reactive forms](guide/reactive-forms) to an app, add the library package using `ng add @angular/forms`, then import the `ReactiveFormsModule` from the `@angular/forms` library in your application code.
|
||||
Similarly, adding the [service worker](guide/service-worker-intro) library to an Angular application is one of the steps for turning an application into a [Progressive Web App](https://developers.google.com/web/progressive-web-apps/) (PWA).
|
||||
[Angular Material](https://material.angular.io/) is an example of a large, general-purpose library that provides sophisticated, reusable, and adaptable UI components.
|
||||
|
||||
Any app developer can use these and other libraries that have been published as npm packages by the Angular team or by third parties. See [Using Published Libraries](guide/using-libraries).
|
||||
|
||||
## Creating libraries
|
||||
|
||||
If you have developed functionality that is suitable for reuse, you can create your own libraries.
|
||||
These libraries can be used locally in your workspace, or you can publish them as [npm packages](guide/npm-packages) to share with other projects or other Angular developers.
|
||||
These packages can be published to the npm registry, a private npm Enterprise registry, or a private package management system that supports npm packages.
|
||||
See [Creating Libraries](guide/creating-libraries).
|
||||
|
||||
Whether you decide to package functionality as a library is an architectural decision, similar to deciding whether a piece of functionality is a component or a service, or deciding on the scope of a component.
|
||||
|
||||
Packaging functionality as a library forces the artifacts in the library to be decoupled from the application's business logic.
|
||||
This can help to avoid various bad practices or architecture mistakes that can make it difficult to decouple and reuse code in the future.
|
||||
|
||||
Putting code into a separate library is more complex than simply putting everything in one app.
|
||||
It requires more of an investment in time and thought for managing, maintaining, and updating the library.
|
||||
This complexity can pay off, however, when the library is being used in multiple apps.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Note that libraries are intended to be used by Angular apps.
|
||||
To add Angular functionality to non-Angular web apps, you can use [Angular custom elements](guide/elements).
|
||||
|
||||
</div>
|
@ -1,37 +1,38 @@
|
||||
# Overview of Angular libraries
|
||||
# Vista general de librerías para Angular
|
||||
|
||||
Many applications need to solve the same general problems, such as presenting a unified user interface, presenting data, and allowing data entry.
|
||||
Developers can create general solutions for particular domains that can be adapted for re-use in different apps.
|
||||
Such a solution can be built as Angular *libraries* and these libraries can be published and shared as *npm packages*.
|
||||
Muchas aplicaciones necesitan resolver los mismos problemas en general, como presentar una interfaz de usuario unificada, mostrar datos, permitir entrada de datos etc.
|
||||
Los desarrolladores puede crear soluciones generales para dominios particulares que pueden ser adoptados para re usarse en diferentes aplicaciones.
|
||||
Tal solución se puede construir como *librerías* para Angular y estas librerías pueden ser publicadas y compartidas como *paquetes de npm*.
|
||||
|
||||
An Angular library is an Angular [project](guide/glossary#project) that differs from an app in that it cannot run on its own.
|
||||
A library must be imported and used in an app.
|
||||
Una librería de Angular es como un [proyecto](guide/glossary#project) lo que la diferencia de una app es que no puede correr por si sola.
|
||||
Una librería debe ser importada y usada en una app.
|
||||
|
||||
Libraries extend Angular's base functionality. For example, to add [reactive forms](guide/reactive-forms) to an app, add the library package using `ng add @angular/forms`, then import the `ReactiveFormsModule` from the `@angular/forms` library in your application code.
|
||||
Similarly, adding the [service worker](guide/service-worker-intro) library to an Angular application is one of the steps for turning an application into a [Progressive Web App](https://developers.google.com/web/progressive-web-apps/) (PWA).
|
||||
[Angular Material](https://material.angular.io/) is an example of a large, general-purpose library that provides sophisticated, reusable, and adaptable UI components.
|
||||
Las librerías extienden la funcionalidad base de Angular. Por ejemplo, para agregar [formularios reactivos](guide/reactive-forms) en una app, agregamos la librería usando `ng add @angular/forms`, entonces importamos el `ReactiveFormsModule` desde la librería `@angular/forms` el código de la aplicación.
|
||||
De igual manera, agregar la librería [service worker](guide/service-worker-intro) dentro de una aplicación Angular es el primer paso para convertir una aplicación a una [Progressive Web App](https://developers.google.com/web/progressive-web-apps/) (PWA).
|
||||
[Angular Material](https://material.angular.io/) es un ejemplo de una gran librería de propósito general que ofrece componentes de UI sofisticados, reutilizables y adaptables.
|
||||
|
||||
Any app developer can use these and other libraries that have been published as npm packages by the Angular team or by third parties. See [Using Published Libraries](guide/using-libraries).
|
||||
Cualquier desarrollador de apps puede usar estas y otras librerías que han sido publicadas como paquetes de npm por el equipo de Angular o por terceros. Mirá [Usando librerías publicadas](guide/using-libraries).
|
||||
|
||||
## Creating libraries
|
||||
## Creando librerías
|
||||
|
||||
If you have developed functionality that is suitable for reuse, you can create your own libraries.
|
||||
These libraries can be used locally in your workspace, or you can publish them as [npm packages](guide/npm-packages) to share with other projects or other Angular developers.
|
||||
These packages can be published to the npm registry, a private npm Enterprise registry, or a private package management system that supports npm packages.
|
||||
See [Creating Libraries](guide/creating-libraries).
|
||||
Si tu tienes funcionalidades desarrolladas que puede ser adecuadas para re usarse tu puedes crear tus propias librerías.
|
||||
Estas librerías puede ser usadas localmente en tu espacio de trabajo, o puede ser publicadas como [paquetes de npm](guide/npm-packages) para compartir con otros proyectos o otros desarrolladores Angular.
|
||||
Estos paquetes pueden ser publicados en el registro de npm, en un registro empresarial privado de npm, o en un sistema de gestión de paquetes privado que soporte paquetes de npm.
|
||||
Mirá [Creando librerías](guide/creating-libraries).
|
||||
|
||||
Whether you decide to package functionality as a library is an architectural decision, similar to deciding whether a piece of functionality is a component or a service, or deciding on the scope of a component.
|
||||
Si tu decides empaquetar una funcionalidad como una librería es una decisión de arquitectura, similar a decidir entre si una pieza de funcionalidad es un componente o un servicio, o decidir el alcance de un componente.
|
||||
|
||||
Packaging functionality as a library forces the artifacts in the library to be decoupled from the application's business logic.
|
||||
This can help to avoid various bad practices or architecture mistakes that can make it difficult to decouple and reuse code in the future.
|
||||
Empaquetar funcionalidad como una librería fuerza a
|
||||
que los artefactos en la librería puedan ser desacoplados de la lógica de negocio de la aplicación.
|
||||
Esto puede ayudar a evitar varias malas practicas o errores de arquitectura que puede hacer difícil desacoplar y re usar código en el futuro.
|
||||
|
||||
Putting code into a separate library is more complex than simply putting everything in one app.
|
||||
It requires more of an investment in time and thought for managing, maintaining, and updating the library.
|
||||
This complexity can pay off, however, when the library is being used in multiple apps.
|
||||
Poniendo el código dentro de una librería separada es más complejo que simplemente poner todo en una sola aplicación.
|
||||
Esto requiere una inversión mayor de tiempo y pensar para administrar, mantener y actualizar la librería.
|
||||
Sin embargo esta complejidad puede valer la pena cuando la librería esta siendo usada en multiples aplicaciones.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Note that libraries are intended to be used by Angular apps.
|
||||
To add Angular functionality to non-Angular web apps, you can use [Angular custom elements](guide/elements).
|
||||
Note que las librerías están destinadas para ser usadas por aplicaciones Angular.
|
||||
Para agregar funcionalidad de Angular hacia una aplicación web que no es Angular, puedes usar [Angular custom elements](guide/elements).
|
||||
|
||||
</div>
|
||||
|
@ -1,13 +1,13 @@
|
||||
# Contributing to resources.json
|
||||
# Contribuir a resources.json
|
||||
|
||||
## About this list
|
||||
We maintain a small list of some of the top Angular resources from across the community, stored in `resources.json`. This list is not intended to be comprehensive, but to act as a starting point to connect Angular developers to the rest of the community.
|
||||
## Acerca de esta lista
|
||||
Mantenemos una pequeña lista de algunos de los principales recursos de Angular de toda la comunidad, almacenados en `resources.json`. Esta lista no pretende ser completa, sino actuar como un punto de partida para conectar a los desarrolladores de Angular con el resto de la comunidad.
|
||||
|
||||
## How do I get listed?
|
||||
While we can't accept all contributions, qualifying contributions can be submitted via a PR adding yourself to the `resources.json` file. All contributions should be in the appropriate section and must meet the following criteria:
|
||||
## ¿Cómo me incluyo?
|
||||
Si bien no podemos aceptar todas las contribuciones, las contribuciones que califiquen se pueden enviar a través de un PR que se agregue al archivo `resources.json`. Todas las contribuciones deben estar en la sección correspondiente y deben cumplir con los siguientes criterios:
|
||||
|
||||
1. Your contribution must be valid, and contain a link to a page talking specifically about using Angular
|
||||
1. Your contribution should have a clear and concise title and description
|
||||
1. Your resource should follow our brand guidelines (see our [Presskit](presskit))
|
||||
1. Your resource should have significant benefit to Angular developers
|
||||
1. Your resource should already have traction and praise from Angular developers
|
||||
1. Su contribución debe ser válida y contener un enlace a una página que hable específicamente sobre el uso de Angular
|
||||
1. Tu contribución debe tener un título y una descripción claros y concisos.
|
||||
1. Su recurso debe seguir nuestras pautas de marca (consulte nuestro [Presskit](presskit))
|
||||
1. Su recurso debería tener un beneficio significativo para los desarrolladores de Angular
|
||||
1. Su recurso ya debería tener tracción y elogios de los desarrolladores de Angular
|
245
aio/content/tutorial/toh-pt1.en.md
Normal file
245
aio/content/tutorial/toh-pt1.en.md
Normal file
@ -0,0 +1,245 @@
|
||||
# The hero editor
|
||||
|
||||
The application now has a basic title.
|
||||
Next you will create a new component to display hero information
|
||||
and place that component in the application shell.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
For the sample app that this page describes, see the <live-example></live-example>.
|
||||
|
||||
</div>
|
||||
|
||||
## Create the heroes component
|
||||
|
||||
Using the Angular CLI, generate a new component named `heroes`.
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate component heroes
|
||||
</code-example>
|
||||
|
||||
The CLI creates a new folder, `src/app/heroes/`, and generates
|
||||
the three files of the `HeroesComponent` along with a test file.
|
||||
|
||||
The `HeroesComponent` class file is as follows:
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1" header="app/heroes/heroes.component.ts (initial version)"></code-example>
|
||||
|
||||
You always import the `Component` symbol from the Angular core library
|
||||
and annotate the component class with `@Component`.
|
||||
|
||||
`@Component` is a decorator function that specifies the Angular metadata for the component.
|
||||
|
||||
The CLI generated three metadata properties:
|
||||
|
||||
1. `selector`— the component's CSS element selector
|
||||
1. `templateUrl`— the location of the component's template file.
|
||||
1. `styleUrls`— the location of the component's private CSS styles.
|
||||
|
||||
{@a selector}
|
||||
|
||||
The [CSS element selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors),
|
||||
`'app-heroes'`, matches the name of the HTML element that identifies this component within a parent component's template.
|
||||
|
||||
The `ngOnInit()` is a [lifecycle hook](guide/lifecycle-hooks#oninit).
|
||||
Angular calls `ngOnInit()` shortly after creating a component.
|
||||
It's a good place to put initialization logic.
|
||||
|
||||
Always `export` the component class so you can `import` it elsewhere ... like in the `AppModule`.
|
||||
|
||||
### Add a `hero` property
|
||||
|
||||
Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm."
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="add-hero" header="heroes.component.ts (hero property)"></code-example>
|
||||
|
||||
### Show the hero
|
||||
|
||||
Open the `heroes.component.html` template file.
|
||||
Delete the default text generated by the Angular CLI and
|
||||
replace it with a data binding to the new `hero` property.
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" header="heroes.component.html" region="show-hero-1"></code-example>
|
||||
|
||||
## Show the `HeroesComponent` view
|
||||
|
||||
To display the `HeroesComponent`, you must add it to the template of the shell `AppComponent`.
|
||||
|
||||
Remember that `app-heroes` is the [element selector](#selector) for the `HeroesComponent`.
|
||||
So add an `<app-heroes>` element to the `AppComponent` template file, just below the title.
|
||||
|
||||
<code-example path="toh-pt1/src/app/app.component.html" header="src/app/app.component.html"></code-example>
|
||||
|
||||
Assuming that the CLI `ng serve` command is still running,
|
||||
the browser should refresh and display both the application title and the hero name.
|
||||
|
||||
## Create a Hero interface
|
||||
|
||||
A real hero is more than a name.
|
||||
|
||||
Create a `Hero` interface in its own file in the `src/app` folder.
|
||||
Give it `id` and `name` properties.
|
||||
|
||||
<code-example path="toh-pt1/src/app/hero.ts" header="src/app/hero.ts"></code-example>
|
||||
|
||||
|
||||
Return to the `HeroesComponent` class and import the `Hero` interface.
|
||||
|
||||
Refactor the component's `hero` property to be of type `Hero`.
|
||||
Initialize it with an `id` of `1` and the name `Windstorm`.
|
||||
|
||||
The revised `HeroesComponent` class file should look like this:
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts"></code-example>
|
||||
|
||||
The page no longer displays properly because you changed the hero from a string to an object.
|
||||
|
||||
## Show the hero object
|
||||
|
||||
Update the binding in the template to announce the hero's name
|
||||
and show both `id` and `name` in a details layout like this:
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" region="show-hero-2" header="heroes.component.html (HeroesComponent's template)"></code-example>
|
||||
|
||||
The browser refreshes and displays the hero's information.
|
||||
|
||||
## Format with the _UppercasePipe_
|
||||
|
||||
Modify the `hero.name` binding like this.
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.html" header="src/app/heroes/heroes.component.html" region="pipe">
|
||||
</code-example>
|
||||
|
||||
The browser refreshes and now the hero's name is displayed in capital letters.
|
||||
|
||||
The word `uppercase` in the interpolation binding,
|
||||
right after the pipe operator ( | ),
|
||||
activates the built-in `UppercasePipe`.
|
||||
|
||||
[Pipes](guide/pipes) are a good way to format strings, currency amounts, dates and other display data.
|
||||
Angular ships with several built-in pipes and you can create your own.
|
||||
|
||||
## Edit the hero
|
||||
|
||||
Users should be able to edit the hero name in an `<input>` textbox.
|
||||
|
||||
The textbox should both _display_ the hero's `name` property
|
||||
and _update_ that property as the user types.
|
||||
That means data flows from the component class _out to the screen_ and
|
||||
from the screen _back to the class_.
|
||||
|
||||
To automate that data flow, setup a two-way data binding between the `<input>` form element and the `hero.name` property.
|
||||
|
||||
### Two-way binding
|
||||
|
||||
Refactor the details area in the `HeroesComponent` template so it looks like this:
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" region="name-input" header="src/app/heroes/heroes.component.html (HeroesComponent's template)"></code-example>
|
||||
|
||||
**[(ngModel)]** is Angular's two-way data binding syntax.
|
||||
|
||||
Here it binds the `hero.name` property to the HTML textbox so that data can flow _in both directions:_ from the `hero.name` property to the textbox, and from the textbox back to the `hero.name`.
|
||||
|
||||
### The missing _FormsModule_
|
||||
|
||||
Notice that the app stopped working when you added `[(ngModel)]`.
|
||||
|
||||
To see the error, open the browser development tools and look in the console
|
||||
for a message like
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
Template parse errors:
|
||||
Can't bind to 'ngModel' since it isn't a known property of 'input'.
|
||||
</code-example>
|
||||
|
||||
Although `ngModel` is a valid Angular directive, it isn't available by default.
|
||||
|
||||
It belongs to the optional `FormsModule` and you must _opt-in_ to using it.
|
||||
|
||||
## _AppModule_
|
||||
|
||||
Angular needs to know how the pieces of your application fit together
|
||||
and what other files and libraries the app requires.
|
||||
This information is called _metadata_.
|
||||
|
||||
Some of the metadata is in the `@Component` decorators that you added to your component classes.
|
||||
Other critical metadata is in [`@NgModule`](guide/ngmodules) decorators.
|
||||
|
||||
The most important `@NgModule` decorator annotates the top-level **AppModule** class.
|
||||
|
||||
The Angular CLI generated an `AppModule` class in `src/app/app.module.ts` when it created the project.
|
||||
This is where you _opt-in_ to the `FormsModule`.
|
||||
|
||||
### Import _FormsModule_
|
||||
|
||||
Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the `@angular/forms` library.
|
||||
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts (FormsModule symbol import)"
|
||||
region="formsmodule-js-import">
|
||||
</code-example>
|
||||
|
||||
Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which contains a list of external modules that the app needs.
|
||||
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts (@NgModule imports)"
|
||||
region="ng-imports">
|
||||
</code-example>
|
||||
|
||||
When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `<h2>` above the textbox.
|
||||
|
||||
### Declare `HeroesComponent`
|
||||
|
||||
Every component must be declared in _exactly one_ [NgModule](guide/ngmodules).
|
||||
|
||||
_You_ didn't declare the `HeroesComponent`.
|
||||
So why did the application work?
|
||||
|
||||
It worked because the Angular CLI declared `HeroesComponent` in the `AppModule` when it generated that component.
|
||||
|
||||
Open `src/app/app.module.ts` and find `HeroesComponent` imported near the top.
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="src/app/app.module.ts" region="heroes-import" >
|
||||
</code-example>
|
||||
|
||||
The `HeroesComponent` is declared in the `@NgModule.declarations` array.
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="src/app/app.module.ts" region="declarations">
|
||||
</code-example>
|
||||
|
||||
Note that `AppModule` declares both application components, `AppComponent` and `HeroesComponent`.
|
||||
|
||||
|
||||
## Final code review
|
||||
|
||||
Here are the code files discussed on this page.
|
||||
|
||||
<code-tabs>
|
||||
|
||||
<code-pane header="src/app/heroes/heroes.component.ts" path="toh-pt1/src/app/heroes/heroes.component.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/heroes/heroes.component.html" path="toh-pt1/src/app/heroes/heroes.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/app.module.ts"
|
||||
path="toh-pt1/src/app/app.module.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/app.component.ts" path="toh-pt1/src/app/app.component.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/app.component.html" path="toh-pt1/src/app/app.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/hero.ts"
|
||||
path="toh-pt1/src/app/hero.ts">
|
||||
</code-pane>
|
||||
|
||||
</code-tabs>
|
||||
|
||||
## Summary
|
||||
|
||||
* You used the CLI to create a second `HeroesComponent`.
|
||||
* You displayed the `HeroesComponent` by adding it to the `AppComponent` shell.
|
||||
* You applied the `UppercasePipe` to format the name.
|
||||
* You used two-way data binding with the `ngModel` directive.
|
||||
* You learned about the `AppModule`.
|
||||
* You imported the `FormsModule` in the `AppModule` so that Angular would recognize and apply the `ngModel` directive.
|
||||
* You learned the importance of declaring components in the `AppModule`
|
||||
and appreciated that the CLI declared it for you.
|
@ -1,213 +1,213 @@
|
||||
# The hero editor
|
||||
# El editor de Héroe
|
||||
|
||||
The application now has a basic title.
|
||||
Next you will create a new component to display hero information
|
||||
and place that component in the application shell.
|
||||
Se ha agregado un título básico a la aplicación.
|
||||
Luego crea un nuevo componente para mostrar la información del héroe,
|
||||
Coloca el componente en el (app shell) de la aplicación.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
For the sample app that this page describes, see the <live-example></live-example>.
|
||||
Para ver la aplicación de ejemplo que describe esta página, consulta el <live-example></live-example>.
|
||||
|
||||
</div>
|
||||
|
||||
## Create the heroes component
|
||||
## Crear un componente de héroes
|
||||
|
||||
Using the Angular CLI, generate a new component named `heroes`.
|
||||
Usa la CLI angular para generar un nuevo componente llamado `heroes`.
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate component heroes
|
||||
</code-example>
|
||||
|
||||
The CLI creates a new folder, `src/app/heroes/`, and generates
|
||||
the three files of the `HeroesComponent` along with a test file.
|
||||
CLI crea una nueva carpeta llamada `src/app/heroes/`, y
|
||||
genera tres archivos sobre `HeroesComponent` junto un archivo de prueba.
|
||||
|
||||
The `HeroesComponent` class file is as follows:
|
||||
El archivo de la clase `HeroesComponent` es el siguiente.
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1" header="app/heroes/heroes.component.ts (initial version)"></code-example>
|
||||
|
||||
You always import the `Component` symbol from the Angular core library
|
||||
and annotate the component class with `@Component`.
|
||||
Siempre Importa el símbolo `Component` de la biblioteca pricipal de Angular, y realiza la anotación a la clase del component con `@Component`.
|
||||
|
||||
`@Component` is a decorator function that specifies the Angular metadata for the component.
|
||||
`@Component` es una decoradoro que especifica metadatos Angular para un
|
||||
componente.
|
||||
|
||||
The CLI generated three metadata properties:
|
||||
La CLI generó 3 propiedades de metadatos:
|
||||
|
||||
1. `selector`— the component's CSS element selector
|
||||
1. `templateUrl`— the location of the component's template file.
|
||||
1. `styleUrls`— the location of the component's private CSS styles.
|
||||
1. `selector`— El selector de elementos CSS para el componente
|
||||
1. `templateUrl`— La ubicación del archivo plantilla para el componente
|
||||
1. `styleUrls`— La ubicación de los estilos CSS privados del componente.
|
||||
|
||||
{@a selector}
|
||||
|
||||
The [CSS element selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors),
|
||||
`'app-heroes'`, matches the name of the HTML element that identifies this component within a parent component's template.
|
||||
El [Selector de elementos CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors)
|
||||
`'app-heroes'`, coincide con el nombre del elemento HTML que identifica este componente en el componente padre Plantillas.
|
||||
|
||||
The `ngOnInit()` is a [lifecycle hook](guide/lifecycle-hooks#oninit).
|
||||
Angular calls `ngOnInit()` shortly after creating a component.
|
||||
It's a good place to put initialization logic.
|
||||
El `ngOnInit()` es un [gancho de ciclo de vida](guide/lifecycle-hooks#oninit) ("lifecycle hook") . Angular llama a `ngOnInit()` inmediatamente después de crear el componente.
|
||||
Adecuado para poner la lógica de inicialización.
|
||||
|
||||
Always `export` the component class so you can `import` it elsewhere ... like in the `AppModule`.
|
||||
Siempre `exporta` la clase de componente, por lo que siempre puede `importarla` en otro lugar, como un `AppModule`.
|
||||
|
||||
### Add a `hero` property
|
||||
### Agrega la propiedad `hero`
|
||||
|
||||
Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm."
|
||||
Agrega una propiedad `hero` al `HeroesComponent` para un héroe llamado "Windstorm".
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="add-hero" header="heroes.component.ts (hero property)"></code-example>
|
||||
|
||||
### Show the hero
|
||||
### Mostrar el héroe
|
||||
|
||||
Open the `heroes.component.html` template file.
|
||||
Delete the default text generated by the Angular CLI and
|
||||
replace it with a data binding to the new `hero` property.
|
||||
Abre el archivo de plantilla `heroes.component.html`.
|
||||
Elimina el texto predeterminado generado por CLI angular,
|
||||
Reemplaza con un enlace de datos a la nueva propiedad `hero`.
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" header="heroes.component.html" region="show-hero-1"></code-example>
|
||||
|
||||
## Show the `HeroesComponent` view
|
||||
## Mostrar la vista `HeroesComponent`
|
||||
|
||||
To display the `HeroesComponent`, you must add it to the template of the shell `AppComponent`.
|
||||
Para ver el `HeroesComponent`, debe agregarlo a las Plantillas en el `AppComponent` del shell de tu aplicación.
|
||||
|
||||
Remember that `app-heroes` is the [element selector](#selector) for the `HeroesComponent`.
|
||||
So add an `<app-heroes>` element to the `AppComponent` template file, just below the title.
|
||||
Recuerda que `app-heroes` es el [selector de elemento](#selector) del `HeroesComponent`.
|
||||
Entonces, en el archivo Plantillas de `AppComponent`, agrega el elemento `<app-heroes>` directamente debajo del título.
|
||||
|
||||
<code-example path="toh-pt1/src/app/app.component.html" header="src/app/app.component.html"></code-example>
|
||||
|
||||
Assuming that the CLI `ng serve` command is still running,
|
||||
the browser should refresh and display both the application title and the hero name.
|
||||
Si el comando CLI `ng serve` todavía se está ejecutando,
|
||||
El navegador se actualiza para mostrar el título de la aplicación y el nombre del héroe.
|
||||
|
||||
## Create a Hero interface
|
||||
## Crear interfaz de héroe
|
||||
|
||||
A real hero is more than a name.
|
||||
Un héroe es más que un nombre.
|
||||
|
||||
Create a `Hero` interface in its own file in the `src/app` folder.
|
||||
Give it `id` and `name` properties.
|
||||
Crea una interfaz `Hero` en su propio archivo en la carpeta `src/app`.
|
||||
Dale una propiedad `id` y una propiedad `name`.
|
||||
|
||||
<code-example path="toh-pt1/src/app/hero.ts" header="src/app/hero.ts"></code-example>
|
||||
|
||||
|
||||
Return to the `HeroesComponent` class and import the `Hero` interface.
|
||||
Regresa a la clase `HeroesComponent` e importe la interfaz `Hero`.
|
||||
|
||||
Refactor the component's `hero` property to be of type `Hero`.
|
||||
Initialize it with an `id` of `1` and the name `Windstorm`.
|
||||
Refactoriza la propiedad de héroe del componente para que sea del tipo 'Héroe'.
|
||||
Inicialízalo con un `id` de `1` y un nombre de `Windstorm`.
|
||||
|
||||
The revised `HeroesComponent` class file should look like this:
|
||||
El archivo de clase revisado `HeroesComponent` se ve así:
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts"></code-example>
|
||||
|
||||
The page no longer displays properly because you changed the hero from a string to an object.
|
||||
Cambió el héroe de texto a un objeto, lo que provocó que la página se mostrara incorrectamente.
|
||||
|
||||
## Show the hero object
|
||||
## Mostrar objeto de héroe
|
||||
|
||||
Update the binding in the template to announce the hero's name
|
||||
and show both `id` and `name` in a details layout like this:
|
||||
Actualiza los enlaces de Plantillas para anunciar el nombre del héroe,
|
||||
Muestra tanto el `id` como el `name` con un diseño detallado como este:
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" region="show-hero-2" header="heroes.component.html (HeroesComponent's template)"></code-example>
|
||||
|
||||
The browser refreshes and displays the hero's information.
|
||||
El navegador se actualiza para mostrar la información del héroe.
|
||||
|
||||
## Format with the _UppercasePipe_
|
||||
## Formatea con _UppercasePipe_
|
||||
|
||||
Modify the `hero.name` binding like this.
|
||||
Modifica el enlace para `hero.name` de esta manera:
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.html" header="src/app/heroes/heroes.component.html" region="pipe">
|
||||
</code-example>
|
||||
|
||||
The browser refreshes and now the hero's name is displayed in capital letters.
|
||||
El navegador se actualizará para mostrar el nombre del héroe en mayúsculas.
|
||||
|
||||
The word `uppercase` in the interpolation binding,
|
||||
right after the pipe operator ( | ),
|
||||
activates the built-in `UppercasePipe`.
|
||||
En el enlace de interpolación, la palabra `mayúscula` inmediatamente después del operador pipe (|) es
|
||||
Inicie el 'UppercasePipe' incorporado.
|
||||
|
||||
[Pipes](guide/pipes) are a good way to format strings, currency amounts, dates and other display data.
|
||||
Angular ships with several built-in pipes and you can create your own.
|
||||
[pipe](guide/pipes) ("pipe") Es adecuado para formatear cadenas, importes monetarios, fechas y otros datos de visualización.
|
||||
Angular viene con múltiples pipes incorporadas, y puede crear las suyas propias.
|
||||
|
||||
## Edit the hero
|
||||
## Editar el héroe
|
||||
|
||||
Users should be able to edit the hero name in an `<input>` textbox.
|
||||
El usuario debe poder editar el nombre del héroe en el cuadro de texto `<input>`.
|
||||
|
||||
The textbox should both _display_ the hero's `name` property
|
||||
and _update_ that property as the user types.
|
||||
That means data flows from the component class _out to the screen_ and
|
||||
from the screen _back to the class_.
|
||||
En el cuadro de texto, la propiedad `name` del héroe se muestra _,
|
||||
La propiedad se actualiza según los tipos de usuario.
|
||||
Esto es de la clase de componente a _screen_,
|
||||
Y significa el flujo de datos desde la pantalla a la clase de componente.
|
||||
|
||||
To automate that data flow, setup a two-way data binding between the `<input>` form element and the `hero.name` property.
|
||||
Para automatizar ese flujo de datos, configure un enlace de datos bidireccional entre el elemento de formulario `<input>` y la propiedad `hero.name`.
|
||||
|
||||
### Two-way binding
|
||||
### Enlace de datos bidireccional
|
||||
|
||||
Refactor the details area in the `HeroesComponent` template so it looks like this:
|
||||
Refactorizando el área de detalle de las Plantas `HeroesComponent` se ve así:
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" region="name-input" header="src/app/heroes/heroes.component.html (HeroesComponent's template)"></code-example>
|
||||
|
||||
**[(ngModel)]** is Angular's two-way data binding syntax.
|
||||
**[(ngModel)]** Es la sintaxis de enlace de datos bidireccional de Angular.
|
||||
|
||||
Here it binds the `hero.name` property to the HTML textbox so that data can flow _in both directions:_ from the `hero.name` property to the textbox, and from the textbox back to the `hero.name`.
|
||||
Esto vinculará la propiedad `hero.name` al cuadro de texto HTML, por lo que
|
||||
Puede pasar datos _en ambas direcciones_ desde la propiedad `hero.name` al cuadro de texto y desde el cuadro de texto a la propiedad `hero.name`.
|
||||
|
||||
### The missing _FormsModule_
|
||||
### _FormsModule_ No encontrado
|
||||
|
||||
Notice that the app stopped working when you added `[(ngModel)]`.
|
||||
Observa que la aplicación dejó de funcionar cuando agregué el `[(ngModel)]`.
|
||||
|
||||
To see the error, open the browser development tools and look in the console
|
||||
for a message like
|
||||
Para ver el error, abre las herramientas de desarrollo de su navegador,
|
||||
Busca mensajes como el siguiente en la consola,
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
Template parse errors:
|
||||
Can't bind to 'ngModel' since it isn't a known property of 'input'.
|
||||
Errores de análisis de plantilla:
|
||||
No se puede vincular a 'nGModelo' ya que no es una propiedad conocida de 'entrada'.
|
||||
</code-example>
|
||||
|
||||
Although `ngModel` is a valid Angular directive, it isn't available by default.
|
||||
`ngModel` Es una directiva angular válida pero no está disponible por defecto.
|
||||
|
||||
It belongs to the optional `FormsModule` and you must _opt-in_ to using it.
|
||||
Pertenece al `FormsModule` opcional y debe optar por ese módulo para usarlo.
|
||||
|
||||
## _AppModule_
|
||||
|
||||
Angular needs to know how the pieces of your application fit together
|
||||
and what other files and libraries the app requires.
|
||||
This information is called _metadata_.
|
||||
En Angular, cómo encajan las partes de la aplicación,
|
||||
Necesita saber qué otros archivos y bibliotecas necesita su aplicación.
|
||||
Esta información se llama _metadata_.
|
||||
|
||||
Some of the metadata is in the `@Component` decorators that you added to your component classes.
|
||||
Other critical metadata is in [`@NgModule`](guide/ngmodules) decorators.
|
||||
Algunos de los metadatos se encuentran en el decorador `@Component` que agregó a su clase de componentes.
|
||||
Otros metadatos importantes son[`@NgModule`](guide/ngmodules)Está en el decorador.
|
||||
|
||||
The most important `@NgModule` decorator annotates the top-level **AppModule** class.
|
||||
El decorador más importante `@NgModule` anota la clase **AppModule** de nivel superior.
|
||||
|
||||
The Angular CLI generated an `AppModule` class in `src/app/app.module.ts` when it created the project.
|
||||
This is where you _opt-in_ to the `FormsModule`.
|
||||
Angular CLI creó la clase `AppModule` en `src/app/app.module.ts` al crear el proyecto.
|
||||
Ahora opta por el `FormsModule`.
|
||||
|
||||
### Import _FormsModule_
|
||||
### Importar _FormsModule_
|
||||
|
||||
Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the `@angular/forms` library.
|
||||
Abre `AppModule` (`app.module.ts`) e importe el símbolo `FormsModule` desde la biblioteca `@angular/forms`.
|
||||
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts (FormsModule symbol import)"
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts (@NgModule imports)"
|
||||
region="formsmodule-js-import">
|
||||
</code-example>
|
||||
|
||||
Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which contains a list of external modules that the app needs.
|
||||
A continuación, agregue el `FormsModule` a el arreglo `imports` de los metadatos `@ NgModule`.
|
||||
Esta matriz contiene una lista de módulos externos que requiere su aplicación.
|
||||
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts (@NgModule imports)"
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts ( @NgModule imports)"
|
||||
region="ng-imports">
|
||||
</code-example>
|
||||
|
||||
When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `<h2>` above the textbox.
|
||||
La aplicación debería funcionar nuevamente cuando se actualice el navegador. Puedes editar el nombre del héroe y ver los cambios reflejados inmediatamente en el `<h2>` arriba del cuadro de texto.
|
||||
|
||||
### Declare `HeroesComponent`
|
||||
### Declarar `HeroesComponent`
|
||||
|
||||
Every component must be declared in _exactly one_ [NgModule](guide/ngmodules).
|
||||
Todos los componentes deben declararse con _exactamente uno_ [NgModule](guide/ngmodules).
|
||||
|
||||
_You_ didn't declare the `HeroesComponent`.
|
||||
So why did the application work?
|
||||
_No has declarado_ HeroesComponent`.
|
||||
Entonces, ¿por qué funcionó la aplicación?
|
||||
|
||||
It worked because the Angular CLI declared `HeroesComponent` in the `AppModule` when it generated that component.
|
||||
La aplicación funcionó porque Angular CLI declaró el componente en el `AppModule` cuando generó el `HeroesComponent`.
|
||||
|
||||
Abra `src/app/app.module.ts` y encuentre el `HeroesComponent` importado cerca de la parte superior.
|
||||
|
||||
Open `src/app/app.module.ts` and find `HeroesComponent` imported near the top.
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="src/app/app.module.ts" region="heroes-import" >
|
||||
</code-example>
|
||||
|
||||
The `HeroesComponent` is declared in the `@NgModule.declarations` array.
|
||||
`HeroesComponent` se declara en la matriz`@NgModule.declarations`.
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="src/app/app.module.ts" region="declarations">
|
||||
</code-example>
|
||||
|
||||
Note that `AppModule` declares both application components, `AppComponent` and `HeroesComponent`.
|
||||
`AppModule` declara los componentes de aplicación `AppComponent` y `HeroesComponent`.
|
||||
|
||||
## Revisión del código final
|
||||
|
||||
## Final code review
|
||||
|
||||
Here are the code files discussed on this page.
|
||||
Los archivos de código descritos en esta página son:
|
||||
|
||||
<code-tabs>
|
||||
|
||||
@ -217,7 +217,7 @@ Here are the code files discussed on this page.
|
||||
<code-pane header="src/app/heroes/heroes.component.html" path="toh-pt1/src/app/heroes/heroes.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/app.module.ts"
|
||||
<code-pane header="src/app/app.module.ts"
|
||||
path="toh-pt1/src/app/app.module.ts">
|
||||
</code-pane>
|
||||
|
||||
@ -232,14 +232,12 @@ Here are the code files discussed on this page.
|
||||
</code-pane>
|
||||
|
||||
</code-tabs>
|
||||
## Resumen
|
||||
|
||||
## Summary
|
||||
|
||||
* You used the CLI to create a second `HeroesComponent`.
|
||||
* You displayed the `HeroesComponent` by adding it to the `AppComponent` shell.
|
||||
* You applied the `UppercasePipe` to format the name.
|
||||
* You used two-way data binding with the `ngModel` directive.
|
||||
* You learned about the `AppModule`.
|
||||
* You imported the `FormsModule` in the `AppModule` so that Angular would recognize and apply the `ngModel` directive.
|
||||
* You learned the importance of declaring components in the `AppModule`
|
||||
and appreciated that the CLI declared it for you.
|
||||
* Creo un segundo `HeroesComponent` usando el CLI.
|
||||
* Agregó `HeroesComponent` al shell de `AppComponent` y lo mostró.
|
||||
* Aplico 'UppercasePipe' para formatear el nombre.
|
||||
* Utilizo el enlace de datos bidireccional en la directiva `ngModel`.
|
||||
* Aprendío sobre `AppModule`.
|
||||
* Importó `FormsModule` en `AppModule` para reconocer y aplicar la directiva Angular `ngModel`.
|
||||
* Aprendío la importancia de declarar un componente en un `AppModule` y me di cuenta de que la CLI está haciendo esa declaración por usted.
|
||||
|
@ -59,7 +59,7 @@ Abre el archivo de clase `HeroDetailComponent` e importe el símbolo `Hero`.
|
||||
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)
|
||||
La propiedad `hero` debe ser una [_propiedad de entrada_](guide/inputs-outputs "Input and Output properties") -->, anotada con el decorador `@Input()` porque el `HeroesComponent` _externo_ [se vinculará de esta manera.](#heroes-component-template)
|
||||
|
||||
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding">
|
||||
</code-example>
|
||||
@ -102,7 +102,7 @@ Vincula `HeroesComponent.selectedHero` a la propiedad `hero` de este elemento de
|
||||
|
||||
</code-example>
|
||||
|
||||
`[hero]="selectedHero"` es el [enlace de propiedad](guide/template-syntax#property-binding). de Angular
|
||||
`[hero]="selectedHero"` es el [enlace de propiedad](guide/property-binding) de Angular.
|
||||
|
||||
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`.
|
||||
@ -156,6 +156,6 @@ Los archivos de código descritos en esta página son:
|
||||
|
||||
* Creaste un `HeroDetailComponent` independiente y reutilizable.
|
||||
|
||||
* Usaste el [enlace de propiedad](guide/template-syntax#property-binding) para que el padre `HeroesComponent` pueda controlar al hijo `HeroDetailComponent`.
|
||||
* Usaste el [enlace de propiedad](guide/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.
|
||||
* Usaste el [`decorador @Input`](guide/inputs-outputs) para hacer que la propiedad del héroe esté disponible para ser vinculada por el componente `HeroesComponent` externamente.
|
||||
|
573
aio/content/tutorial/toh-pt5.en.md
Normal file
573
aio/content/tutorial/toh-pt5.en.md
Normal file
@ -0,0 +1,573 @@
|
||||
# Add in-app navigation with routing
|
||||
|
||||
There are new requirements for the Tour of Heroes app:
|
||||
|
||||
* Add a *Dashboard* view.
|
||||
* Add the ability to navigate between the *Heroes* and *Dashboard* views.
|
||||
* When users click a hero name in either view, navigate to a detail view of the selected hero.
|
||||
* When users click a *deep link* in an email, open the detail view for a particular hero.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
For the sample app that this page describes, see the <live-example></live-example>.
|
||||
|
||||
</div>
|
||||
|
||||
When you’re done, users will be able to navigate the app like this:
|
||||
|
||||
<div class="lightbox">
|
||||
<img src='generated/images/guide/toh/nav-diagram.png' alt="View navigations">
|
||||
</div>
|
||||
|
||||
## Add the `AppRoutingModule`
|
||||
|
||||
In Angular, the best practice is to load and configure the router in a separate, top-level module
|
||||
that is dedicated to routing and imported by the root `AppModule`.
|
||||
|
||||
By convention, the module class name is `AppRoutingModule` and it belongs in the `app-routing.module.ts` in the `src/app` folder.
|
||||
|
||||
Use the CLI to generate it.
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate module app-routing --flat --module=app
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
`--flat` puts the file in `src/app` instead of its own folder.<br>
|
||||
`--module=app` tells the CLI to register it in the `imports` array of the `AppModule`.
|
||||
</div>
|
||||
|
||||
The generated file looks like this:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.0.ts" header="src/app/app-routing.module.ts (generated)">
|
||||
</code-example>
|
||||
|
||||
Replace it with the following:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.1.ts" header="src/app/app-routing.module.ts (updated)">
|
||||
</code-example>
|
||||
|
||||
First, `AppRoutingModule` imports `RouterModule` and `Routes` so the app can have routing functionality. The next import, `HeroesComponent`, will give the Router somewhere to go once you configure the routes.
|
||||
|
||||
Notice that the `CommonModule` references and `declarations` array are unnecessary, so are no
|
||||
longer part of `AppRoutingModule`. The following sections explain the rest of the `AppRoutingModule` in more detail.
|
||||
|
||||
|
||||
### Routes
|
||||
|
||||
The next part of the file is where you configure your routes.
|
||||
*Routes* tell the Router which view to display when a user clicks a link or
|
||||
pastes a URL into the browser address bar.
|
||||
|
||||
Since `AppRoutingModule` already imports `HeroesComponent`, you can use it in the `routes` array:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts"
|
||||
region="heroes-route">
|
||||
</code-example>
|
||||
|
||||
A typical Angular `Route` has two properties:
|
||||
|
||||
* `path`: a string that matches the URL in the browser address bar.
|
||||
* `component`: the component that the router should create when navigating to this route.
|
||||
|
||||
This tells the router to match that URL to `path: 'heroes'`
|
||||
and display the `HeroesComponent` when the URL is something like `localhost:4200/heroes`.
|
||||
|
||||
### `RouterModule.forRoot()`
|
||||
|
||||
The `@NgModule` metadata initializes the router and starts it listening for browser location changes.
|
||||
|
||||
The following line adds the `RouterModule` to the `AppRoutingModule` `imports` array and
|
||||
configures it with the `routes` in one step by calling
|
||||
`RouterModule.forRoot()`:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="ngmodule-imports">
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The method is called `forRoot()` because you configure the router at the application's root level.
|
||||
The `forRoot()` method supplies the service providers and directives needed for routing,
|
||||
and performs the initial navigation based on the current browser URL.
|
||||
|
||||
</div>
|
||||
|
||||
Next, `AppRoutingModule` exports `RouterModule` so it will be available throughout the app.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts (exports array)" region="export-routermodule">
|
||||
</code-example>
|
||||
|
||||
## Add `RouterOutlet`
|
||||
|
||||
Open the `AppComponent` template and replace the `<app-heroes>` element with a `<router-outlet>` element.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app.component.html" region="outlet" header="src/app/app.component.html (router-outlet)">
|
||||
</code-example>
|
||||
|
||||
The `AppComponent` template no longer needs `<app-heroes>` because the app will only display the `HeroesComponent` when the user navigates to it.
|
||||
|
||||
The `<router-outlet>` tells the router where to display routed views.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The `RouterOutlet` is one of the router directives that became available to the `AppComponent`
|
||||
because `AppModule` imports `AppRoutingModule` which exported `RouterModule`. The `ng generate` command you ran at the start of this tutorial added this import because of the `--module=app` flag. If you manually created `app-routing.module.ts` or used a tool other than the CLI to do so, you'll need to import `AppRoutingModule` into `app.module.ts` and add it to the `imports` array of the `NgModule`.
|
||||
|
||||
</div>
|
||||
|
||||
#### Try it
|
||||
|
||||
You should still be running with this CLI command.
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng serve
|
||||
</code-example>
|
||||
|
||||
The browser should refresh and display the app title but not the list of heroes.
|
||||
|
||||
Look at the browser's address bar.
|
||||
The URL ends in `/`.
|
||||
The route path to `HeroesComponent` is `/heroes`.
|
||||
|
||||
Append `/heroes` to the URL in the browser address bar.
|
||||
You should see the familiar heroes master/detail view.
|
||||
|
||||
{@a routerlink}
|
||||
|
||||
## Add a navigation link (`routerLink`)
|
||||
|
||||
Ideally, users should be able to click a link to navigate rather
|
||||
than pasting a route URL into the address bar.
|
||||
|
||||
Add a `<nav>` element and, within that, an anchor element that, when clicked,
|
||||
triggers navigation to the `HeroesComponent`.
|
||||
The revised `AppComponent` template looks like this:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app.component.html" region="heroes" header="src/app/app.component.html (heroes RouterLink)">
|
||||
</code-example>
|
||||
|
||||
A [`routerLink` attribute](#routerlink) is set to `"/heroes"`,
|
||||
the string that the router matches to the route to `HeroesComponent`.
|
||||
The `routerLink` is the selector for the [`RouterLink` directive](/api/router/RouterLink)
|
||||
that turns user clicks into router navigations.
|
||||
It's another of the public directives in the `RouterModule`.
|
||||
|
||||
The browser refreshes and displays the app title and heroes link,
|
||||
but not the heroes list.
|
||||
|
||||
Click the link.
|
||||
The address bar updates to `/heroes` and the list of heroes appears.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Make this and future navigation links look better by adding private CSS styles to `app.component.css`
|
||||
as listed in the [final code review](#appcomponent) below.
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## Add a dashboard view
|
||||
|
||||
Routing makes more sense when there are multiple views.
|
||||
So far there's only the heroes view.
|
||||
|
||||
Add a `DashboardComponent` using the CLI:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate component dashboard
|
||||
</code-example>
|
||||
|
||||
The CLI generates the files for the `DashboardComponent` and declares it in `AppModule`.
|
||||
|
||||
Replace the default file content in these three files as follows:
|
||||
|
||||
<code-tabs>
|
||||
<code-pane
|
||||
header="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.1.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane
|
||||
header="src/app/dashboard/dashboard.component.ts" path="toh-pt5/src/app/dashboard/dashboard.component.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane
|
||||
header="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css">
|
||||
</code-pane>
|
||||
</code-tabs>
|
||||
|
||||
The _template_ presents a grid of hero name links.
|
||||
|
||||
* The `*ngFor` repeater creates as many links as are in the component's `heroes` array.
|
||||
* The links are styled as colored blocks by the `dashboard.component.css`.
|
||||
* The links don't go anywhere yet but [they will shortly](#hero-details).
|
||||
|
||||
The _class_ is similar to the `HeroesComponent` class.
|
||||
* It defines a `heroes` array property.
|
||||
* The constructor expects Angular to inject the `HeroService` into a private `heroService` property.
|
||||
* The `ngOnInit()` lifecycle hook calls `getHeroes()`.
|
||||
|
||||
This `getHeroes()` returns the sliced list of heroes at positions 1 and 5, returning only four of the Top Heroes (2nd, 3rd, 4th, and 5th).
|
||||
|
||||
<code-example path="toh-pt5/src/app/dashboard/dashboard.component.ts" header="src/app/dashboard/dashboard.component.ts" region="getHeroes">
|
||||
</code-example>
|
||||
|
||||
### Add the dashboard route
|
||||
|
||||
To navigate to the dashboard, the router needs an appropriate route.
|
||||
|
||||
Import the `DashboardComponent` in the `AppRoutingModule`.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="import-dashboard" header="src/app/app-routing.module.ts (import DashboardComponent)">
|
||||
</code-example>
|
||||
|
||||
Add a route to the `AppRoutingModule.routes` array that matches a path to the `DashboardComponent`.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="dashboard-route">
|
||||
</code-example>
|
||||
|
||||
### Add a default route
|
||||
|
||||
When the app starts, the browser's address bar points to the web site's root.
|
||||
That doesn't match any existing route so the router doesn't navigate anywhere.
|
||||
The space below the `<router-outlet>` is blank.
|
||||
|
||||
To make the app navigate to the dashboard automatically, add the following
|
||||
route to the `AppRoutingModule.Routes` array.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="redirect-route">
|
||||
</code-example>
|
||||
|
||||
This route redirects a URL that fully matches the empty path to the route whose path is `'/dashboard'`.
|
||||
|
||||
After the browser refreshes, the router loads the `DashboardComponent`
|
||||
and the browser address bar shows the `/dashboard` URL.
|
||||
|
||||
### Add dashboard link to the shell
|
||||
|
||||
The user should be able to navigate back and forth between the
|
||||
`DashboardComponent` and the `HeroesComponent` by clicking links in the
|
||||
navigation area near the top of the page.
|
||||
|
||||
Add a dashboard navigation link to the `AppComponent` shell template, just above the *Heroes* link.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app.component.html" header="src/app/app.component.html">
|
||||
</code-example>
|
||||
|
||||
After the browser refreshes you can navigate freely between the two views by clicking the links.
|
||||
|
||||
{@a hero-details}
|
||||
## Navigating to hero details
|
||||
|
||||
The `HeroDetailsComponent` displays details of a selected hero.
|
||||
At the moment the `HeroDetailsComponent` is only visible at the bottom of the `HeroesComponent`
|
||||
|
||||
The user should be able to get to these details in three ways.
|
||||
|
||||
1. By clicking a hero in the dashboard.
|
||||
1. By clicking a hero in the heroes list.
|
||||
1. By pasting a "deep link" URL into the browser address bar that identifies the hero to display.
|
||||
|
||||
In this section, you'll enable navigation to the `HeroDetailsComponent`
|
||||
and liberate it from the `HeroesComponent`.
|
||||
|
||||
### Delete _hero details_ from `HeroesComponent`
|
||||
|
||||
When the user clicks a hero item in the `HeroesComponent`,
|
||||
the app should navigate to the `HeroDetailComponent`,
|
||||
replacing the heroes list view with the hero detail view.
|
||||
The heroes list view should no longer show hero details as it does now.
|
||||
|
||||
Open the `HeroesComponent` template (`heroes/heroes.component.html`) and
|
||||
delete the `<app-hero-detail>` element from the bottom.
|
||||
|
||||
Clicking a hero item now does nothing.
|
||||
You'll [fix that shortly](#heroes-component-links) after you enable routing to the `HeroDetailComponent`.
|
||||
|
||||
### Add a _hero detail_ route
|
||||
|
||||
A URL like `~/detail/11` would be a good URL for navigating to the *Hero Detail* view of the hero whose `id` is `11`.
|
||||
|
||||
Open `AppRoutingModule` and import `HeroDetailComponent`.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="import-herodetail" header="src/app/app-routing.module.ts (import HeroDetailComponent)">
|
||||
</code-example>
|
||||
|
||||
Then add a _parameterized_ route to the `AppRoutingModule.routes` array that matches the path pattern to the _hero detail_ view.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="detail-route">
|
||||
</code-example>
|
||||
|
||||
The colon (:) in the `path` indicates that `:id` is a placeholder for a specific hero `id`.
|
||||
|
||||
At this point, all application routes are in place.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="routes" header="src/app/app-routing.module.ts (all routes)">
|
||||
</code-example>
|
||||
|
||||
### `DashboardComponent` hero links
|
||||
|
||||
The `DashboardComponent` hero links do nothing at the moment.
|
||||
|
||||
Now that the router has a route to `HeroDetailComponent`,
|
||||
fix the dashboard hero links to navigate via the _parameterized_ dashboard route.
|
||||
|
||||
<code-example
|
||||
path="toh-pt5/src/app/dashboard/dashboard.component.html"
|
||||
region="click"
|
||||
header="src/app/dashboard/dashboard.component.html (hero links)">
|
||||
</code-example>
|
||||
|
||||
You're using Angular [interpolation binding](guide/interpolation) within the `*ngFor` repeater
|
||||
to insert the current iteration's `hero.id` into each
|
||||
[`routerLink`](#routerlink).
|
||||
|
||||
{@a heroes-component-links}
|
||||
### `HeroesComponent` hero links
|
||||
|
||||
The hero items in the `HeroesComponent` are `<li>` elements whose click events
|
||||
are bound to the component's `onSelect()` method.
|
||||
|
||||
<code-example path="toh-pt4/src/app/heroes/heroes.component.html" region="list" header="src/app/heroes/heroes.component.html (list with onSelect)">
|
||||
</code-example>
|
||||
|
||||
Strip the `<li>` back to just its `*ngFor`,
|
||||
wrap the badge and name in an anchor element (`<a>`),
|
||||
and add a `routerLink` attribute to the anchor that
|
||||
is the same as in the dashboard template
|
||||
|
||||
<code-example path="toh-pt5/src/app/heroes/heroes.component.html" region="list" header="src/app/heroes/heroes.component.html (list with links)">
|
||||
</code-example>
|
||||
|
||||
You'll have to fix the private stylesheet (`heroes.component.css`) to make
|
||||
the list look as it did before.
|
||||
Revised styles are in the [final code review](#heroescomponent) at the bottom of this guide.
|
||||
|
||||
#### Remove dead code (optional)
|
||||
|
||||
While the `HeroesComponent` class still works,
|
||||
the `onSelect()` method and `selectedHero` property are no longer used.
|
||||
|
||||
It's nice to tidy up and you'll be grateful to yourself later.
|
||||
Here's the class after pruning away the dead code.
|
||||
|
||||
<code-example path="toh-pt5/src/app/heroes/heroes.component.ts" region="class" header="src/app/heroes/heroes.component.ts (cleaned up)">
|
||||
</code-example>
|
||||
|
||||
## Routable `HeroDetailComponent`
|
||||
|
||||
Previously, the parent `HeroesComponent` set the `HeroDetailComponent.hero`
|
||||
property and the `HeroDetailComponent` displayed the hero.
|
||||
|
||||
`HeroesComponent` doesn't do that anymore.
|
||||
Now the router creates the `HeroDetailComponent` in response to a URL such as `~/detail/11`.
|
||||
|
||||
The `HeroDetailComponent` needs a new way to obtain the hero-to-display.
|
||||
This section explains the following:
|
||||
|
||||
* Get the route that created it
|
||||
* Extract the `id` from the route
|
||||
* Acquire the hero with that `id` from the server via the `HeroService`
|
||||
|
||||
Add the following imports:
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="added-imports" header="src/app/hero-detail/hero-detail.component.ts">
|
||||
</code-example>
|
||||
|
||||
{@a hero-detail-ctor}
|
||||
|
||||
Inject the `ActivatedRoute`, `HeroService`, and `Location` services
|
||||
into the constructor, saving their values in private fields:
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" header="src/app/hero-detail/hero-detail.component.ts" region="ctor">
|
||||
</code-example>
|
||||
|
||||
The [`ActivatedRoute`](api/router/ActivatedRoute) holds information about the route to this instance of the `HeroDetailComponent`.
|
||||
This component is interested in the route's parameters extracted from the URL.
|
||||
The "id" parameter is the `id` of the hero to display.
|
||||
|
||||
The [`HeroService`](tutorial/toh-pt4) gets hero data from the remote server
|
||||
and this component will use it to get the hero-to-display.
|
||||
|
||||
The [`location`](api/common/Location) is an Angular service for interacting with the browser.
|
||||
You'll use it [later](#goback) to navigate back to the view that navigated here.
|
||||
|
||||
### Extract the `id` route parameter
|
||||
|
||||
In the `ngOnInit()` [lifecycle hook](guide/lifecycle-hooks#oninit)
|
||||
call `getHero()` and define it as follows.
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" header="src/app/hero-detail/hero-detail.component.ts" region="ngOnInit">
|
||||
</code-example>
|
||||
|
||||
The `route.snapshot` is a static image of the route information shortly after the component was created.
|
||||
|
||||
The `paramMap` is a dictionary of route parameter values extracted from the URL.
|
||||
The `"id"` key returns the `id` of the hero to fetch.
|
||||
|
||||
Route parameters are always strings.
|
||||
The JavaScript (+) operator converts the string to a number,
|
||||
which is what a hero `id` should be.
|
||||
|
||||
The browser refreshes and the app crashes with a compiler error.
|
||||
`HeroService` doesn't have a `getHero()` method.
|
||||
Add it now.
|
||||
|
||||
### Add `HeroService.getHero()`
|
||||
|
||||
Open `HeroService` and add the following `getHero()` method with the `id` after the `getHeroes()` method:
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero.service.ts" region="getHero" header="src/app/hero.service.ts (getHero)">
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
Note the backticks ( ` ) that define a JavaScript
|
||||
[_template literal_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) for embedding the `id`.
|
||||
</div>
|
||||
|
||||
Like [`getHeroes()`](tutorial/toh-pt4#observable-heroservice),
|
||||
`getHero()` has an asynchronous signature.
|
||||
It returns a _mock hero_ as an `Observable`, using the RxJS `of()` function.
|
||||
|
||||
You'll be able to re-implement `getHero()` as a real `Http` request
|
||||
without having to change the `HeroDetailComponent` that calls it.
|
||||
|
||||
#### Try it
|
||||
|
||||
The browser refreshes and the app is working again.
|
||||
You can click a hero in the dashboard or in the heroes list and navigate to that hero's detail view.
|
||||
|
||||
If you paste `localhost:4200/detail/11` in the browser address bar,
|
||||
the router navigates to the detail view for the hero with `id: 11`, "Dr Nice".
|
||||
|
||||
{@a goback}
|
||||
|
||||
### Find the way back
|
||||
|
||||
By clicking the browser's back button,
|
||||
you can go back to the hero list or dashboard view,
|
||||
depending upon which sent you to the detail view.
|
||||
|
||||
It would be nice to have a button on the `HeroDetail` view that can do that.
|
||||
|
||||
Add a *go back* button to the bottom of the component template and bind it
|
||||
to the component's `goBack()` method.
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.html" region="back-button" header="src/app/hero-detail/hero-detail.component.html (back button)">
|
||||
</code-example>
|
||||
|
||||
Add a `goBack()` _method_ to the component class that navigates backward one step
|
||||
in the browser's history stack
|
||||
using the `Location` service that you [injected previously](#hero-detail-ctor).
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="goBack" header="src/app/hero-detail/hero-detail.component.ts (goBack)">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
Refresh the browser and start clicking.
|
||||
Users can navigate around the app, from the dashboard to hero details and back,
|
||||
from heroes list to the mini detail to the hero details and back to the heroes again.
|
||||
|
||||
## Final code review
|
||||
|
||||
Here are the code files discussed on this page.
|
||||
|
||||
{@a approutingmodule}
|
||||
{@a appmodule}
|
||||
#### `AppRoutingModule`, `AppModule`, and `HeroService`
|
||||
|
||||
<code-tabs>
|
||||
<code-pane
|
||||
header="src/app/app-routing.module.ts"
|
||||
path="toh-pt5/src/app/app-routing.module.ts">
|
||||
</code-pane>
|
||||
<code-pane
|
||||
header="src/app/app.module.ts"
|
||||
path="toh-pt5/src/app/app.module.ts">
|
||||
</code-pane>
|
||||
<code-pane
|
||||
header="src/app/hero.service.ts"
|
||||
path="toh-pt5/src/app/hero.service.ts">
|
||||
</code-pane>
|
||||
</code-tabs>
|
||||
|
||||
{@a appcomponent}
|
||||
#### `AppComponent`
|
||||
|
||||
<code-tabs>
|
||||
<code-pane
|
||||
header="src/app/app.component.html"
|
||||
path="toh-pt5/src/app/app.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane
|
||||
header="src/app/app.component.css"
|
||||
path="toh-pt5/src/app/app.component.css">
|
||||
</code-pane>
|
||||
</code-tabs>
|
||||
|
||||
{@a dashboardcomponent}
|
||||
#### `DashboardComponent`
|
||||
|
||||
<code-tabs>
|
||||
<code-pane
|
||||
header="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane
|
||||
header="src/app/dashboard/dashboard.component.ts" path="toh-pt5/src/app/dashboard/dashboard.component.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane
|
||||
header="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css">
|
||||
</code-pane>
|
||||
</code-tabs>
|
||||
|
||||
{@a heroescomponent}
|
||||
#### `HeroesComponent`
|
||||
|
||||
<code-tabs>
|
||||
<code-pane
|
||||
header="src/app/heroes/heroes.component.html" path="toh-pt5/src/app/heroes/heroes.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane
|
||||
header="src/app/heroes/heroes.component.ts"
|
||||
path="toh-pt5/src/app/heroes/heroes.component.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane
|
||||
header="src/app/heroes/heroes.component.css"
|
||||
path="toh-pt5/src/app/heroes/heroes.component.css">
|
||||
</code-pane>
|
||||
</code-tabs>
|
||||
|
||||
{@a herodetailcomponent}
|
||||
#### `HeroDetailComponent`
|
||||
|
||||
<code-tabs>
|
||||
<code-pane
|
||||
header="src/app/hero-detail/hero-detail.component.html" path="toh-pt5/src/app/hero-detail/hero-detail.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane
|
||||
header="src/app/hero-detail/hero-detail.component.ts" path="toh-pt5/src/app/hero-detail/hero-detail.component.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane
|
||||
header="src/app/hero-detail/hero-detail.component.css" path="toh-pt5/src/app/hero-detail/hero-detail.component.css">
|
||||
</code-pane>
|
||||
</code-tabs>
|
||||
|
||||
## Summary
|
||||
|
||||
* You added the Angular router to navigate among different components.
|
||||
* You turned the `AppComponent` into a navigation shell with `<a>` links and a `<router-outlet>`.
|
||||
* You configured the router in an `AppRoutingModule`
|
||||
* You defined simple routes, a redirect route, and a parameterized route.
|
||||
* You used the `routerLink` directive in anchor elements.
|
||||
* You refactored a tightly-coupled master/detail view into a routed detail view.
|
||||
* You used router link parameters to navigate to the detail view of a user-selected hero.
|
||||
* You shared the `HeroService` among multiple components.
|
@ -1,32 +1,32 @@
|
||||
# Add in-app navigation with routing
|
||||
# Agregar navegación en la aplicación con enrutamiento
|
||||
|
||||
There are new requirements for the Tour of Heroes app:
|
||||
Hay nuevos requisitos para la aplicación Tour of Heroes:
|
||||
|
||||
* Add a *Dashboard* view.
|
||||
* Add the ability to navigate between the *Heroes* and *Dashboard* views.
|
||||
* When users click a hero name in either view, navigate to a detail view of the selected hero.
|
||||
* When users click a *deep link* in an email, open the detail view for a particular hero.
|
||||
* Agregar una vista de *Panel de control*.
|
||||
* Agregue la capacidad de navegar entre las vistas *Heroes* y *Dashboard*.
|
||||
* Cuando los usuarios hacen clic en el nombre de un héroe en cualquiera de las vistas, navega a una vista detallada del héroe seleccionado.
|
||||
* Cuando los usuarios hacen clic en un *enlace profundo* en un correo electrónico, abre la vista detallada de un héroe en particular.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
For the sample app that this page describes, see the <live-example></live-example>.
|
||||
Para ver la aplicación de ejemplo que describe esta página, consulte el<live-example></live-example>.
|
||||
|
||||
</div>
|
||||
|
||||
When you’re done, users will be able to navigate the app like this:
|
||||
Cuando haya terminado, los usuarios podrán navegar por la aplicación de esta manera:
|
||||
|
||||
<div class="lightbox">
|
||||
<img src='generated/images/guide/toh/nav-diagram.png' alt="View navigations">
|
||||
</div>
|
||||
|
||||
## Add the `AppRoutingModule`
|
||||
## Agregar el `AppRoutingModule`
|
||||
|
||||
In Angular, the best practice is to load and configure the router in a separate, top-level module
|
||||
that is dedicated to routing and imported by the root `AppModule`.
|
||||
En Angular, la mejor práctica es cargar y configurar el enrutador en un módulo de nivel superior separado
|
||||
que está dedicado al enrutamiento e importado por la raíz `AppModule`.
|
||||
|
||||
By convention, the module class name is `AppRoutingModule` and it belongs in the `app-routing.module.ts` in the `src/app` folder.
|
||||
Por convención, el nombre de la clase del módulo es `AppRoutingModule` y pertenece a `app-routing.module.ts` en la carpeta `src/app`.
|
||||
|
||||
Use the CLI to generate it.
|
||||
Utiliza el CLI para generarlo.
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate module app-routing --flat --module=app
|
||||
@ -34,52 +34,51 @@ Use the CLI to generate it.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
`--flat` puts the file in `src/app` instead of its own folder.<br>
|
||||
`--module=app` tells the CLI to register it in the `imports` array of the `AppModule`.
|
||||
`--flat` coloca el archivo en `src/app` en lugar de en su propia carpeta. <br>
|
||||
`--module=app` le dice a la CLI que lo registre en la matriz de `importaciones` del `AppModule`.
|
||||
</div>
|
||||
|
||||
The generated file looks like this:
|
||||
El archivo generado se ve así:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.0.ts" header="src/app/app-routing.module.ts (generated)">
|
||||
</code-example>
|
||||
|
||||
Replace it with the following:
|
||||
Reemplácelo con lo siguiente:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.1.ts" header="src/app/app-routing.module.ts (updated)">
|
||||
</code-example>
|
||||
|
||||
First, `AppRoutingModule` imports `RouterModule` and `Routes` so the app can have routing functionality. The next import, `HeroesComponent`, will give the Router somewhere to go once you configure the routes.
|
||||
Primero, `AppRoutingModule` importa `RouterModule` y `Routes` para que la aplicación pueda tener funcionalidad de enrutamiento. La siguiente importación, `HeroesComponent`, le dará al enrutador un lugar adonde ir una vez que configure las rutas.
|
||||
|
||||
Notice that the `CommonModule` references and `declarations` array are unnecessary, so are no
|
||||
longer part of `AppRoutingModule`. The following sections explain the rest of the `AppRoutingModule` in more detail.
|
||||
Ten en cuenta que las referencias de CommonModule y la matriz de declaraciones son innecesarias, por lo que no
|
||||
parte más larga de `AppRoutingModule`. Las siguientes secciones explican el resto del `AppRoutingModule` con más detalle.
|
||||
|
||||
### Rutas
|
||||
|
||||
### Routes
|
||||
La siguiente parte del archivo es donde configura sus rutas.
|
||||
*Rutas* le indican al enrutador qué vista mostrar cuando un usuario hace clic en un enlace o
|
||||
pega una URL en la barra de direcciones del navegador.
|
||||
|
||||
The next part of the file is where you configure your routes.
|
||||
*Routes* tell the Router which view to display when a user clicks a link or
|
||||
pastes a URL into the browser address bar.
|
||||
|
||||
Since `AppRoutingModule` already imports `HeroesComponent`, you can use it in the `routes` array:
|
||||
Como `AppRoutingModule` ya importa `HeroesComponent`, puedes usarlo en la matriz de `rutas`:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts"
|
||||
region="heroes-route">
|
||||
</code-example>
|
||||
|
||||
A typical Angular `Route` has two properties:
|
||||
Una `Ruta` típica de Angular tiene dos propiedades:
|
||||
|
||||
* `path`: a string that matches the URL in the browser address bar.
|
||||
* `component`: the component that the router should create when navigating to this route.
|
||||
* `path`: una cadena que coincide con la URL en la barra de direcciones del navegador.
|
||||
* `componet`: el componente que el enrutador debe crear al navegar a esta ruta.
|
||||
|
||||
This tells the router to match that URL to `path: 'heroes'`
|
||||
and display the `HeroesComponent` when the URL is something like `localhost:4200/heroes`.
|
||||
Esto le dice al enrutador que haga coincidir esa URL con `path: 'héroes'`
|
||||
y mostrar el `HeroesComponent` cuando la URL sea algo como `localhost:4200/heroes`.
|
||||
|
||||
### `RouterModule.forRoot()`
|
||||
|
||||
The `@NgModule` metadata initializes the router and starts it listening for browser location changes.
|
||||
Los metadatos `@NgModule` inicializan el enrutador y lo hacen escuchar los cambios de ubicación del navegador.
|
||||
|
||||
The following line adds the `RouterModule` to the `AppRoutingModule` `imports` array and
|
||||
configures it with the `routes` in one step by calling
|
||||
La siguiente línea agrega el `RouterModule` a la matriz `AppRoutingModule` `importa` y
|
||||
lo configura con las `rutas` en un solo paso llamando
|
||||
`RouterModule.forRoot()`:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="ngmodule-imports">
|
||||
@ -87,100 +86,99 @@ configures it with the `routes` in one step by calling
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The method is called `forRoot()` because you configure the router at the application's root level.
|
||||
The `forRoot()` method supplies the service providers and directives needed for routing,
|
||||
and performs the initial navigation based on the current browser URL.
|
||||
El método se llama `forRoot()` porque configura el enrutador en el nivel raíz de la aplicación.
|
||||
El método `forRoot()` proporciona los proveedores de servicios y las directivas necesarias para el enrutamiento,
|
||||
y realiza la navegación inicial basada en la URL del navegador actual.
|
||||
|
||||
</div>
|
||||
|
||||
Next, `AppRoutingModule` exports `RouterModule` so it will be available throughout the app.
|
||||
A continuación, `AppRoutingModule` exporta `RouterModule` para que esté disponible en toda la aplicación.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts (exports array)" region="export-routermodule">
|
||||
</code-example>
|
||||
|
||||
## Add `RouterOutlet`
|
||||
## Agregar `RouterOutlet`
|
||||
|
||||
Open the `AppComponent` template and replace the `<app-heroes>` element with a `<router-outlet>` element.
|
||||
Abre la plantilla `AppComponent` y reemplaza el elemento `<app-heroes>` con un elemento `<router-outlet>`.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app.component.html" region="outlet" header="src/app/app.component.html (router-outlet)">
|
||||
</code-example>
|
||||
|
||||
The `AppComponent` template no longer needs `<app-heroes>` because the app will only display the `HeroesComponent` when the user navigates to it.
|
||||
La plantilla `AppComponent` ya no necesita `<app-heroes>` porque la aplicación solo mostrará el `HeroesComponent` cuando el usuario navegue hacia él.
|
||||
|
||||
The `<router-outlet>` tells the router where to display routed views.
|
||||
El `<router-outlet>` le dice al enrutador dónde mostrar las vistas enrutadas.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The `RouterOutlet` is one of the router directives that became available to the `AppComponent`
|
||||
because `AppModule` imports `AppRoutingModule` which exported `RouterModule`. The `ng generate` command you ran at the start of this tutorial added this import because of the `--module=app` flag. If you manually created `app-routing.module.ts` or used a tool other than the CLI to do so, you'll need to import `AppRoutingModule` into `app.module.ts` and add it to the `imports` array of the `NgModule`.
|
||||
El `RouterOutlet` es una de las directivas del enrutador que estuvo disponible para el `AppComponent`
|
||||
porque `AppModule` importa `AppRoutingModule` que exportó `RouterModule`. El comando `ng generate` que ejecutó al comienzo de este tutorial agregó esta importación debido a la marca `--module=app`. Si creó manualmente `app-routing.module.ts` o usó una herramienta que no sea la CLI para hacerlo, deberá importar `AppRoutingModule` a `app.module.ts` y agregarlo a las `importaciones` matriz del `NgModule`.
|
||||
|
||||
</div>
|
||||
|
||||
#### Try it
|
||||
#### Pruébalo
|
||||
|
||||
You should still be running with this CLI command.
|
||||
Debería seguir ejecutando este comando CLI.
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng serve
|
||||
</code-example>
|
||||
|
||||
The browser should refresh and display the app title but not the list of heroes.
|
||||
El navegador debería actualizar y mostrar el título de la aplicación, pero no la lista de héroes.
|
||||
|
||||
Look at the browser's address bar.
|
||||
The URL ends in `/`.
|
||||
The route path to `HeroesComponent` is `/heroes`.
|
||||
Mira la barra de direcciones del navegador.
|
||||
La URL termina en `/`.
|
||||
La ruta de acceso a `HeroesComponent` es `/heroes`.
|
||||
|
||||
Append `/heroes` to the URL in the browser address bar.
|
||||
You should see the familiar heroes master/detail view.
|
||||
Agrega `/heroes` a la URL en la barra de direcciones del navegador.
|
||||
Debería ver la vista maestra / detallada de héroes familiares.
|
||||
|
||||
{@a routerlink}
|
||||
|
||||
## Add a navigation link (`routerLink`)
|
||||
## Agregar un enlace de navegación (`routerLink`)
|
||||
|
||||
Ideally, users should be able to click a link to navigate rather
|
||||
than pasting a route URL into the address bar.
|
||||
Idealmente, los usuarios deberían poder hacer clic en un enlace para navegar en lugar de
|
||||
que pegar una URL de ruta en la barra de direcciones.
|
||||
|
||||
Add a `<nav>` element and, within that, an anchor element that, when clicked,
|
||||
triggers navigation to the `HeroesComponent`.
|
||||
The revised `AppComponent` template looks like this:
|
||||
Agrega un elemento `<nav>` y, dentro de él, un elemento de ancla que, al hacer clic,
|
||||
activa la navegación al `HeroesComponent`.
|
||||
La plantilla `AppComponent` revisada se ve así:
|
||||
|
||||
<code-example path="toh-pt5/src/app/app.component.html" region="heroes" header="src/app/app.component.html (heroes RouterLink)">
|
||||
</code-example>
|
||||
|
||||
A [`routerLink` attribute](#routerlink) is set to `"/heroes"`,
|
||||
the string that the router matches to the route to `HeroesComponent`.
|
||||
The `routerLink` is the selector for the [`RouterLink` directive](/api/router/RouterLink)
|
||||
that turns user clicks into router navigations.
|
||||
It's another of the public directives in the `RouterModule`.
|
||||
Un [atributo `routerLink`](#routerlink) se establece en `"/heroes"`,
|
||||
la cadena que el enrutador coincide con la ruta a `HeroesComponent`.
|
||||
El `routerLink` es el selector para la [directiva `RouterLink`](/api/router/RouterLink)
|
||||
que convierte los clics del usuario en navegaciones del enrutador.
|
||||
Es otra de las directivas públicas del `RouterModule`.
|
||||
|
||||
The browser refreshes and displays the app title and heroes link,
|
||||
but not the heroes list.
|
||||
El navegador se actualiza y muestra el título de la aplicación y el enlace de héroes.
|
||||
pero no la lista de héroes.
|
||||
|
||||
Click the link.
|
||||
The address bar updates to `/heroes` and the list of heroes appears.
|
||||
Haz clic en el enlace.
|
||||
La barra de direcciones se actualiza a `/heroes` y aparece la lista de héroes.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Make this and future navigation links look better by adding private CSS styles to `app.component.css`
|
||||
as listed in the [final code review](#appcomponent) below.
|
||||
Hace que este y los enlaces de navegación futuros se vean mejor agregando estilos CSS privados a `app.component.css`
|
||||
como se indica en la [revisión final del código](#appcomponent) a continuación.
|
||||
|
||||
</div>
|
||||
|
||||
## Agregar una vista de panel
|
||||
|
||||
## Add a dashboard view
|
||||
El enrutamiento tiene más sentido cuando hay varias vistas.
|
||||
Hasta ahora solo existe la vista de héroes.
|
||||
|
||||
Routing makes more sense when there are multiple views.
|
||||
So far there's only the heroes view.
|
||||
|
||||
Add a `DashboardComponent` using the CLI:
|
||||
Agrega un `DashboardComponent` usando la CLI:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate component dashboard
|
||||
</code-example>
|
||||
|
||||
The CLI generates the files for the `DashboardComponent` and declares it in `AppModule`.
|
||||
La CLI genera los archivos para el `DashboardComponent` y lo declara en `AppModule`.
|
||||
|
||||
Replace the default file content in these three files as follows:
|
||||
Reemplaza el contenido del archivo predeterminado en estos tres archivos de la siguiente manera:
|
||||
|
||||
<code-tabs>
|
||||
<code-pane
|
||||
@ -196,121 +194,121 @@ Replace the default file content in these three files as follows:
|
||||
</code-pane>
|
||||
</code-tabs>
|
||||
|
||||
The _template_ presents a grid of hero name links.
|
||||
La _plantilla_ presenta una cuadrícula de enlaces de nombres de héroes.
|
||||
|
||||
* The `*ngFor` repeater creates as many links as are in the component's `heroes` array.
|
||||
* The links are styled as colored blocks by the `dashboard.component.css`.
|
||||
* The links don't go anywhere yet but [they will shortly](#hero-details).
|
||||
* El repetidor `* ngFor` crea tantos enlaces como hay en en el arreglo `heroes` del componente.
|
||||
* Los enlaces están diseñados como bloques de colores por el `dashboard.component.css`.
|
||||
* Los enlaces no van a ninguna parte todavía, pero [lo harán en breve](#hero-details).
|
||||
|
||||
The _class_ is similar to the `HeroesComponent` class.
|
||||
* It defines a `heroes` array property.
|
||||
* The constructor expects Angular to inject the `HeroService` into a private `heroService` property.
|
||||
* The `ngOnInit()` lifecycle hook calls `getHeroes()`.
|
||||
La _clase_ es similar a la clase `HeroesComponent`.
|
||||
* Define una propiedad de matriz de héroes.
|
||||
* El constructor espera que Angular inyecte el `HeroService` en una propiedad privada de `heroService`.
|
||||
* El gancho del ciclo de vida `ngOnInit()` llama a `getHeroes()`.
|
||||
|
||||
This `getHeroes()` returns the sliced list of heroes at positions 1 and 5, returning only four of the Top Heroes (2nd, 3rd, 4th, and 5th).
|
||||
Este `getHeroes()` devuelve la lista dividida de héroes en las posiciones 1 y 5, devolviendo solo cuatro de los mejores héroes (segundo, tercero, cuarto y quinto).
|
||||
|
||||
<code-example path="toh-pt5/src/app/dashboard/dashboard.component.ts" header="src/app/dashboard/dashboard.component.ts" region="getHeroes">
|
||||
</code-example>
|
||||
|
||||
### Add the dashboard route
|
||||
### Agregar la ruta del tablero(dashboard)
|
||||
|
||||
To navigate to the dashboard, the router needs an appropriate route.
|
||||
Para navegar hasta el tablero, el enrutador necesita una ruta adecuada.
|
||||
|
||||
Import the `DashboardComponent` in the `AppRoutingModule`.
|
||||
Importa el `DashboardComponent` en el `AppRoutingModule`.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="import-dashboard" header="src/app/app-routing.module.ts (import DashboardComponent)">
|
||||
</code-example>
|
||||
|
||||
Add a route to the `AppRoutingModule.routes` array that matches a path to the `DashboardComponent`.
|
||||
Agrega una ruta a la matriz `AppRoutingModule.routes` que coincida con una ruta al `DashboardComponent`.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="dashboard-route">
|
||||
</code-example>
|
||||
|
||||
### Add a default route
|
||||
### Agregar una ruta predeterminada
|
||||
|
||||
When the app starts, the browser's address bar points to the web site's root.
|
||||
That doesn't match any existing route so the router doesn't navigate anywhere.
|
||||
The space below the `<router-outlet>` is blank.
|
||||
Cuando se inicia la aplicación, la barra de direcciones del navegador apunta a la raíz del sitio web.
|
||||
Eso no coincide con ninguna ruta existente, por lo que el enrutador no navega a ninguna parte.
|
||||
El espacio debajo de `<router-outlet>` está en blanco.
|
||||
|
||||
To make the app navigate to the dashboard automatically, add the following
|
||||
route to the `AppRoutingModule.Routes` array.
|
||||
Para que la aplicación navegue al panel de control automáticamente, agreaga la siguiente
|
||||
ruta a la matriz `AppRoutingModule.Routes`.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="redirect-route">
|
||||
</code-example>
|
||||
|
||||
This route redirects a URL that fully matches the empty path to the route whose path is `'/dashboard'`.
|
||||
Esta ruta redirige una URL que coincide completamente con la ruta vacía a la ruta cuya ruta es `'/dashboard'`.
|
||||
|
||||
After the browser refreshes, the router loads the `DashboardComponent`
|
||||
and the browser address bar shows the `/dashboard` URL.
|
||||
Después de que el navegador se actualiza, el enrutador carga el `DashboardComponent`
|
||||
y la barra de direcciones del navegador muestra la URL `/dashboard`.
|
||||
|
||||
### Add dashboard link to the shell
|
||||
### Agregar enlace del tablero al caparazón
|
||||
|
||||
The user should be able to navigate back and forth between the
|
||||
`DashboardComponent` and the `HeroesComponent` by clicking links in the
|
||||
navigation area near the top of the page.
|
||||
El usuario debe poder navegar hacia adelante y hacia atrás entre
|
||||
`DashboardComponent` y `HeroesComponent` haciendo clic en los enlaces en el
|
||||
área de navegación cerca de la parte superior de la página.
|
||||
|
||||
Add a dashboard navigation link to the `AppComponent` shell template, just above the *Heroes* link.
|
||||
Agrega un enlace de navegación del panel de control a la plantilla de caparazón `AppComponent`, justo encima del enlace *Heroes*.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app.component.html" header="src/app/app.component.html">
|
||||
</code-example>
|
||||
|
||||
After the browser refreshes you can navigate freely between the two views by clicking the links.
|
||||
Después de que se actualice el navegador, puedes navegar libremente entre las dos vistas haciendo clic en los enlaces.
|
||||
|
||||
{@a hero-details}
|
||||
## Navigating to hero details
|
||||
## Navegando a los detalles del héroe
|
||||
|
||||
The `HeroDetailsComponent` displays details of a selected hero.
|
||||
At the moment the `HeroDetailsComponent` is only visible at the bottom of the `HeroesComponent`
|
||||
El `HeroDetailsComponent` muestra los detalles de un héroe seleccionado.
|
||||
Por el momento, el `HeroDetailsComponent` solo es visible en la parte inferior del `HeroesComponent`
|
||||
|
||||
The user should be able to get to these details in three ways.
|
||||
El usuario debería poder acceder a estos detalles de tres formas.
|
||||
|
||||
1. By clicking a hero in the dashboard.
|
||||
1. By clicking a hero in the heroes list.
|
||||
1. By pasting a "deep link" URL into the browser address bar that identifies the hero to display.
|
||||
1. Haciendo clic en un héroe en el tablero.
|
||||
1. Haciendo clic en un héroe de la lista de héroes.
|
||||
1. Pegando una URL de "enlace profundo" en la barra de direcciones del navegador que identifica al héroe a mostrar.
|
||||
|
||||
In this section, you'll enable navigation to the `HeroDetailsComponent`
|
||||
and liberate it from the `HeroesComponent`.
|
||||
En esta sección, habilitará la navegación al `HeroDetailsComponent`
|
||||
y libérelo del `HeroesComponent`.
|
||||
|
||||
### Delete _hero details_ from `HeroesComponent`
|
||||
### Eliminar _detalles de héroe_ de `HeroesComponent`
|
||||
|
||||
When the user clicks a hero item in the `HeroesComponent`,
|
||||
the app should navigate to the `HeroDetailComponent`,
|
||||
replacing the heroes list view with the hero detail view.
|
||||
The heroes list view should no longer show hero details as it does now.
|
||||
Cuando el usuario hace clic en un elemento de héroe en el `HeroesComponent`,
|
||||
la aplicación debería navegar hasta el `HeroDetailComponent`,
|
||||
reemplazando la vista de lista de héroes con la vista de detalles de héroe.
|
||||
La vista de lista de héroes ya no debería mostrar los detalles de los héroes como lo hace ahora.
|
||||
|
||||
Open the `HeroesComponent` template (`heroes/heroes.component.html`) and
|
||||
delete the `<app-hero-detail>` element from the bottom.
|
||||
Abre la plantilla `HeroesComponent` (`heroes/heroes.component.html`) y
|
||||
elimine el elemento `<app-hero-detail>` de la parte inferior.
|
||||
|
||||
Clicking a hero item now does nothing.
|
||||
You'll [fix that shortly](#heroes-component-links) after you enable routing to the `HeroDetailComponent`.
|
||||
Hacer clic en un elemento de héroe ahora no hace nada.
|
||||
Lo [arreglará en breve](#heroes-component-links) después de habilitar el enrutamiento al `HeroDetailComponent`.
|
||||
|
||||
### Add a _hero detail_ route
|
||||
### Agregar una ruta _detalle del héroe_
|
||||
|
||||
A URL like `~/detail/11` would be a good URL for navigating to the *Hero Detail* view of the hero whose `id` is `11`.
|
||||
Una URL como `~/detail/11` sería una buena URL para navegar a la vista *Hero Detail* del héroe cuyo `id` es `11`.
|
||||
|
||||
Open `AppRoutingModule` and import `HeroDetailComponent`.
|
||||
Abre `AppRoutingModule` e importe `HeroDetailComponent`.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="import-herodetail" header="src/app/app-routing.module.ts (import HeroDetailComponent)">
|
||||
</code-example>
|
||||
|
||||
Then add a _parameterized_ route to the `AppRoutingModule.routes` array that matches the path pattern to the _hero detail_ view.
|
||||
Luego, agrega una ruta _parametrizada_ a la matriz `AppRoutingModule.routes` que coincida con el patrón de ruta de la vista _detalle del héroe_.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="detail-route">
|
||||
</code-example>
|
||||
|
||||
The colon (:) in the `path` indicates that `:id` is a placeholder for a specific hero `id`.
|
||||
Los dos puntos (:) en el `path` indican que `: id` es un marcador de posición para un `id` de héroe específico.
|
||||
|
||||
At this point, all application routes are in place.
|
||||
En este punto, todas las rutas de aplicación están en su lugar.
|
||||
|
||||
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="routes" header="src/app/app-routing.module.ts (all routes)">
|
||||
</code-example>
|
||||
|
||||
### `DashboardComponent` hero links
|
||||
### Enlaces de héroe de `DashboardComponent`
|
||||
|
||||
The `DashboardComponent` hero links do nothing at the moment.
|
||||
Los enlaces de héroe `DashboardComponent` no hacen nada en este momento.
|
||||
|
||||
Now that the router has a route to `HeroDetailComponent`,
|
||||
fix the dashboard hero links to navigate via the _parameterized_ dashboard route.
|
||||
Ahora que el enrutador tiene una ruta a `HeroDetailComponent`,
|
||||
Corrige los enlaces del héroe del tablero para navegar a través de la ruta del tablero _parameterized_.
|
||||
|
||||
<code-example
|
||||
path="toh-pt5/src/app/dashboard/dashboard.component.html"
|
||||
@ -318,161 +316,161 @@ fix the dashboard hero links to navigate via the _parameterized_ dashboard route
|
||||
header="src/app/dashboard/dashboard.component.html (hero links)">
|
||||
</code-example>
|
||||
|
||||
You're using Angular [interpolation binding](guide/interpolation) within the `*ngFor` repeater
|
||||
to insert the current iteration's `hero.id` into each
|
||||
[`routerLink`](#routerlink).
|
||||
Estás usando el [enlace de interpolación](guide/interpolation) Angular dentro del repetidor `*ngFor`
|
||||
para insertar el `hero.id` de la iteración actual en cada
|
||||
[`enlace del enrutador`](#routerlink).
|
||||
|
||||
{@a heroes-component-links}
|
||||
### `HeroesComponent` hero links
|
||||
### Enlaces de héroe de `HeroesComponent`
|
||||
|
||||
The hero items in the `HeroesComponent` are `<li>` elements whose click events
|
||||
are bound to the component's `onSelect()` method.
|
||||
Los elementos de héroe en el `HeroesComponent` son elementos` <li> `cuyos eventos de clic
|
||||
están vinculados al método `onSelect()` del componente.
|
||||
|
||||
<code-example path="toh-pt4/src/app/heroes/heroes.component.html" region="list" header="src/app/heroes/heroes.component.html (list with onSelect)">
|
||||
</code-example>
|
||||
|
||||
Strip the `<li>` back to just its `*ngFor`,
|
||||
wrap the badge and name in an anchor element (`<a>`),
|
||||
and add a `routerLink` attribute to the anchor that
|
||||
is the same as in the dashboard template
|
||||
Quita el `<li>` de nuevo a su `* ngFor`,
|
||||
envuelve la insignia y el nombre en un elemento de anclaje (`<a>`),
|
||||
y agrega un atributo `routerLink` al ancla que
|
||||
es el mismo que en la plantilla del panel
|
||||
|
||||
<code-example path="toh-pt5/src/app/heroes/heroes.component.html" region="list" header="src/app/heroes/heroes.component.html (list with links)">
|
||||
</code-example>
|
||||
|
||||
You'll have to fix the private stylesheet (`heroes.component.css`) to make
|
||||
the list look as it did before.
|
||||
Revised styles are in the [final code review](#heroescomponent) at the bottom of this guide.
|
||||
Tendrás que arreglar la hoja de estilo privada (`heroes.component.css`) para hacer
|
||||
la lista tiene el mismo aspecto que antes.
|
||||
Los estilos revisados se encuentran en la [revisión final del código](#heroescomponent) al final de esta guía.
|
||||
|
||||
#### Remove dead code (optional)
|
||||
#### Eliminar código muerto (opcional)
|
||||
|
||||
While the `HeroesComponent` class still works,
|
||||
the `onSelect()` method and `selectedHero` property are no longer used.
|
||||
Si bien la clase `HeroesComponent` todavía funciona,
|
||||
el método `onSelect()` y la propiedad `selectedHero` ya no se utilizan.
|
||||
|
||||
It's nice to tidy up and you'll be grateful to yourself later.
|
||||
Here's the class after pruning away the dead code.
|
||||
Es agradable poner en orden y te lo agradecerás más tarde.
|
||||
Aquí está la clase después de podar el código muerto.
|
||||
|
||||
<code-example path="toh-pt5/src/app/heroes/heroes.component.ts" region="class" header="src/app/heroes/heroes.component.ts (cleaned up)">
|
||||
</code-example>
|
||||
|
||||
## Routable `HeroDetailComponent`
|
||||
## `HeroDetailComponent` enrutable
|
||||
|
||||
Previously, the parent `HeroesComponent` set the `HeroDetailComponent.hero`
|
||||
property and the `HeroDetailComponent` displayed the hero.
|
||||
Anteriormente, el padre `HeroesComponent` configuraba el `HeroDetailComponent.hero`
|
||||
propiedad y el `HeroDetailComponent` mostraba el héroe.
|
||||
|
||||
`HeroesComponent` doesn't do that anymore.
|
||||
Now the router creates the `HeroDetailComponent` in response to a URL such as `~/detail/11`.
|
||||
`HeroesComponent` ya no hace eso.
|
||||
Ahora el enrutador crea el `HeroDetailComponent` en respuesta a una URL como `~/detail/11`.
|
||||
|
||||
The `HeroDetailComponent` needs a new way to obtain the hero-to-display.
|
||||
This section explains the following:
|
||||
El `HeroDetailComponent` necesita una nueva forma de obtener el héroe a mostrar.
|
||||
Esta sección explica lo siguiente:
|
||||
|
||||
* Get the route that created it
|
||||
* Extract the `id` from the route
|
||||
* Acquire the hero with that `id` from the server via the `HeroService`
|
||||
* Obtén la ruta que lo creó
|
||||
* Extrae el `id` de la ruta
|
||||
* Adquirir el héroe con ese "id" del servidor a través de "HeroService"
|
||||
|
||||
Add the following imports:
|
||||
Agrega las siguientes importaciones:
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="added-imports" header="src/app/hero-detail/hero-detail.component.ts">
|
||||
</code-example>
|
||||
|
||||
{@a hero-detail-ctor}
|
||||
|
||||
Inject the `ActivatedRoute`, `HeroService`, and `Location` services
|
||||
into the constructor, saving their values in private fields:
|
||||
Inyecta los servicios `ActivatedRoute`, `HeroService` y `Location`
|
||||
en el constructor, guardando sus valores en campos privados:
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" header="src/app/hero-detail/hero-detail.component.ts" region="ctor">
|
||||
</code-example>
|
||||
|
||||
The [`ActivatedRoute`](api/router/ActivatedRoute) holds information about the route to this instance of the `HeroDetailComponent`.
|
||||
This component is interested in the route's parameters extracted from the URL.
|
||||
The "id" parameter is the `id` of the hero to display.
|
||||
El [`ActivatedRoute`](api/router/ActivatedRoute) contiene información sobre la ruta a esta instancia del `HeroDetailComponent`.
|
||||
Este componente está interesado en los parámetros de la ruta extraídos de la URL.
|
||||
El parámetro "id" es el `id` del héroe que se mostrará.
|
||||
|
||||
The [`HeroService`](tutorial/toh-pt4) gets hero data from the remote server
|
||||
and this component will use it to get the hero-to-display.
|
||||
El [`HeroService`](tutorial/toh-pt4) obtiene los datos del héroe del servidor remoto
|
||||
y este componente lo usará para mostrar el héroe.
|
||||
|
||||
The [`location`](api/common/Location) is an Angular service for interacting with the browser.
|
||||
You'll use it [later](#goback) to navigate back to the view that navigated here.
|
||||
La [`ubicación`](api/common/Location) es un servicio Angular para interactuar con el navegador.
|
||||
Lo usarás [más tarde](#goback) para volver a la vista que navegó aquí.
|
||||
|
||||
### Extract the `id` route parameter
|
||||
### Extrae el parámetro de ruta `id`
|
||||
|
||||
In the `ngOnInit()` [lifecycle hook](guide/lifecycle-hooks#oninit)
|
||||
call `getHero()` and define it as follows.
|
||||
En el `ngOnInit()` [gancho del ciclo de vida](guide/lifecycle-hooks#oninit)
|
||||
llama a `getHero()` y defínalo de la siguiente manera.
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" header="src/app/hero-detail/hero-detail.component.ts" region="ngOnInit">
|
||||
</code-example>
|
||||
|
||||
The `route.snapshot` is a static image of the route information shortly after the component was created.
|
||||
`Route.snapshot` es una imagen estática de la información de la ruta poco después de que se creó el componente.
|
||||
|
||||
The `paramMap` is a dictionary of route parameter values extracted from the URL.
|
||||
The `"id"` key returns the `id` of the hero to fetch.
|
||||
El `paramMap` es un diccionario de valores de parámetros de ruta extraídos de la URL.
|
||||
La clave `"id"` devuelve el `id` del héroe a buscar.
|
||||
|
||||
Route parameters are always strings.
|
||||
The JavaScript (+) operator converts the string to a number,
|
||||
which is what a hero `id` should be.
|
||||
Los parámetros de ruta son siempre cadenas.
|
||||
El operador JavaScript (+) convierte la cadena en un número,
|
||||
que es lo que debería ser un "id" de héroe.
|
||||
|
||||
The browser refreshes and the app crashes with a compiler error.
|
||||
`HeroService` doesn't have a `getHero()` method.
|
||||
Add it now.
|
||||
El navegador se actualiza y la aplicación se bloquea con un error del compilador.
|
||||
`HeroService` no tiene un método `getHero()`.
|
||||
Agréguelo ahora.
|
||||
|
||||
### Add `HeroService.getHero()`
|
||||
### Agregar `HeroService.getHero ()`
|
||||
|
||||
Open `HeroService` and add the following `getHero()` method with the `id` after the `getHeroes()` method:
|
||||
Abre `HeroService` y agrega el siguiente método `getHero()` con el `id` después del método `getHeroes ()`:
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero.service.ts" region="getHero" header="src/app/hero.service.ts (getHero)">
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
Note the backticks ( ` ) that define a JavaScript
|
||||
[_template literal_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) for embedding the `id`.
|
||||
Ten en cuenta las comillas invertidas (`) que definen un JavaScript
|
||||
[_plantilla literal_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) para incrustar el `id`.
|
||||
|
||||
</div>
|
||||
|
||||
Like [`getHeroes()`](tutorial/toh-pt4#observable-heroservice),
|
||||
`getHero()` has an asynchronous signature.
|
||||
It returns a _mock hero_ as an `Observable`, using the RxJS `of()` function.
|
||||
Como [`getHeroes()`](tutorial/toh-pt4#observable-heroservice),
|
||||
`getHero()` tiene una firma asincrónica.
|
||||
Devuelve un _mock hero_ como un `Observable`, usando la función RxJS `of()`.
|
||||
|
||||
You'll be able to re-implement `getHero()` as a real `Http` request
|
||||
without having to change the `HeroDetailComponent` that calls it.
|
||||
Podrá volver a implementar `getHero()` como una solicitud real de `Http`
|
||||
sin tener que cambiar el `HeroDetailComponent` que lo llama.
|
||||
|
||||
#### Try it
|
||||
#### Pruébalo
|
||||
|
||||
The browser refreshes and the app is working again.
|
||||
You can click a hero in the dashboard or in the heroes list and navigate to that hero's detail view.
|
||||
El navegador se actualiza y la aplicación vuelve a funcionar.
|
||||
Puedes hacer clic en un héroe en el tablero o en la lista de héroes y navegar hasta la vista de detalles de ese héroe.
|
||||
|
||||
If you paste `localhost:4200/detail/11` in the browser address bar,
|
||||
the router navigates to the detail view for the hero with `id: 11`, "Dr Nice".
|
||||
Si pega `localhost:4200/detail/11` en la barra de direcciones del navegador,
|
||||
el enrutador navega a la vista detallada del héroe con `id: 11`," Dr Nice ".
|
||||
|
||||
{@a goback}
|
||||
|
||||
### Find the way back
|
||||
### Encuentra el camino de regreso
|
||||
|
||||
By clicking the browser's back button,
|
||||
you can go back to the hero list or dashboard view,
|
||||
depending upon which sent you to the detail view.
|
||||
Al hacer clic en el botón Atrás del navegador,
|
||||
puede volver a la lista de héroes o la vista del panel,
|
||||
dependiendo de cuál le envió a la vista detallada.
|
||||
|
||||
It would be nice to have a button on the `HeroDetail` view that can do that.
|
||||
Sería bueno tener un botón en la vista `HeroDetail` que pueda hacer eso.
|
||||
|
||||
Add a *go back* button to the bottom of the component template and bind it
|
||||
to the component's `goBack()` method.
|
||||
Agrega un botón *volver* en la parte inferior de la plantilla del componente y vincúlalo
|
||||
al método `goBack()` del componente.
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.html" region="back-button" header="src/app/hero-detail/hero-detail.component.html (back button)">
|
||||
</code-example>
|
||||
|
||||
Add a `goBack()` _method_ to the component class that navigates backward one step
|
||||
in the browser's history stack
|
||||
using the `Location` service that you [injected previously](#hero-detail-ctor).
|
||||
Agrega un método `goBack()` a la clase de componente que navega hacia atrás un paso
|
||||
en la pila de historial del navegador
|
||||
usando el servicio `Location` que [inyectaste previamente](#hero-detail-ctor).
|
||||
|
||||
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="goBack" header="src/app/hero-detail/hero-detail.component.ts (goBack)">
|
||||
|
||||
</code-example>
|
||||
|
||||
Actualiza el navegador y comience a hacer clic.
|
||||
Los usuarios pueden navegar por la aplicación, desde el panel hasta los detalles del héroe y viceversa,
|
||||
de la lista de héroes al mini detalle a los detalles del héroe y de regreso a los héroes nuevamente.
|
||||
|
||||
Refresh the browser and start clicking.
|
||||
Users can navigate around the app, from the dashboard to hero details and back,
|
||||
from heroes list to the mini detail to the hero details and back to the heroes again.
|
||||
## Revisión final del código
|
||||
|
||||
## Final code review
|
||||
|
||||
Here are the code files discussed on this page.
|
||||
Aquí están los archivos de código discutidos en esta página.
|
||||
|
||||
{@a approutingmodule}
|
||||
{@a appmodule}
|
||||
@ -561,13 +559,13 @@ Here are the code files discussed on this page.
|
||||
</code-pane>
|
||||
</code-tabs>
|
||||
|
||||
## Summary
|
||||
## Resumen
|
||||
|
||||
* You added the Angular router to navigate among different components.
|
||||
* You turned the `AppComponent` into a navigation shell with `<a>` links and a `<router-outlet>`.
|
||||
* You configured the router in an `AppRoutingModule`
|
||||
* You defined simple routes, a redirect route, and a parameterized route.
|
||||
* You used the `routerLink` directive in anchor elements.
|
||||
* You refactored a tightly-coupled master/detail view into a routed detail view.
|
||||
* You used router link parameters to navigate to the detail view of a user-selected hero.
|
||||
* You shared the `HeroService` among multiple components.
|
||||
* Agregó el enrutador Angular para navegar entre diferentes componentes.
|
||||
* Convirtió el `AppComponent` en un caparazón de navegación con enlaces `<a>`y un `<router-outlet>`.
|
||||
* Configuró el enrutador en un `AppRoutingModule`
|
||||
* Definió rutas simples, una ruta de redireccionamiento y una ruta parametrizada.
|
||||
* Usó la directiva `routerLink` en elementos de anclaje.
|
||||
* Refactorizó una vista maestra/detallada estrechamente acoplada en una vista de detalle enrutada.
|
||||
* Usó parámetros de enlace del enrutador para navegar a la vista detallada de un héroe seleccionado por el usuario.
|
||||
* Compartió el "HeroService" entre varios componentes.
|
||||
|
@ -12,7 +12,7 @@ describe('site App', function() {
|
||||
it('should show features text after clicking "Features"', () => {
|
||||
page.navigateTo('');
|
||||
page.click(page.getTopMenuLink('features'));
|
||||
expect(page.getDocViewerText()).toMatch(/Progressive web apps/i);
|
||||
expect(page.getDocViewerText()).toMatch(/Aplicaciones Web Progresivas/i);
|
||||
});
|
||||
|
||||
it('should set appropriate window titles', () => {
|
||||
@ -20,7 +20,7 @@ describe('site App', function() {
|
||||
expect(browser.getTitle()).toBe('Angular');
|
||||
|
||||
page.click(page.getTopMenuLink('features'));
|
||||
expect(browser.getTitle()).toBe('Angular - FEATURES & BENEFITS');
|
||||
expect(browser.getTitle()).toBe('Angular - FUNCIONALIDADES & VENTAJAS');
|
||||
|
||||
page.click(page.homeLink);
|
||||
expect(browser.getTitle()).toBe('Angular');
|
||||
@ -79,7 +79,7 @@ describe('site App', function() {
|
||||
|
||||
// navigate to a different page
|
||||
page.click(page.getTopMenuLink('features'));
|
||||
expect(page.getDocViewerText()).toMatch(/Progressive web apps/i);
|
||||
expect(page.getDocViewerText()).toMatch(/Aplicaciones Web Progresivas/i);
|
||||
|
||||
// Show the menu
|
||||
page.click(page.docsMenuLink);
|
||||
@ -87,7 +87,7 @@ describe('site App', function() {
|
||||
// Tutorial folder should still be expanded because this test runs in wide mode
|
||||
// Navigate to the tutorial introduction via a link in the sidenav
|
||||
page.click(page.getNavItem(/El Editor de Héroe/i));
|
||||
expect(page.getDocViewerText()).toMatch(/The hero editor/i);
|
||||
expect(page.getDocViewerText()).toMatch(/El editor de Héroe/i);
|
||||
});
|
||||
|
||||
it('should render `{@example}` dgeni tags as `<code-example>` elements with HTML escaped content', () => {
|
||||
|
Reference in New Issue
Block a user