docs: translate tutorial/toh-pt4.md (#86)

* Toh pt4

- Se agrego la versión en ingles .en.md
- Se Probo previamente

* corrección ortografica y de enlaces colgantes
This commit is contained in:
Antonio Cardenas 2020-10-21 09:19:21 -06:00 committed by GitHub
parent b44f7b1a5c
commit 45e6bb4a74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 631 additions and 180 deletions

View File

@ -0,0 +1,446 @@
# Add services
The Tour of Heroes `HeroesComponent` is currently getting and displaying fake data.
After the refactoring in this tutorial, `HeroesComponent` will be lean and focused on supporting the view.
It will also be easier to unit-test with a mock service.
<div class="alert is-helpful">
For the sample app that this page describes, see the <live-example></live-example>.
</div>
## Why services
Components shouldn't fetch or save data directly and they certainly shouldn't knowingly present fake data.
They should focus on presenting data and delegate data access to a service.
In this tutorial, you'll create a `HeroService` that all application classes can use to get heroes.
Instead of creating that service with the [`new` keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new),
you'll rely on Angular [*dependency injection*](guide/dependency-injection)
to inject it into the `HeroesComponent` constructor.
Services are a great way to share information among classes that _don't know each other_.
You'll create a `MessageService` and inject it in two places.
1. Inject in HeroService, which uses the service to send a message.
2. Inject in MessagesComponent, which displays that message, and also displays the ID
when the user clicks a hero.
## Create the `HeroService`
Using the Angular CLI, create a service called `hero`.
<code-example language="sh" class="code-shell">
ng generate service hero
</code-example>
The command generates a skeleton `HeroService` class in `src/app/hero.service.ts` as follows:
<code-example path="toh-pt4/src/app/hero.service.1.ts" region="new"
header="src/app/hero.service.ts (new service)"></code-example>
### `@Injectable()` services
Notice that the new service imports the Angular `Injectable` symbol and annotates
the class with the `@Injectable()` decorator. This marks the class as one that participates in the _dependency injection system_. The `HeroService` class is going to provide an injectable service, and it can also have its own injected dependencies.
It doesn't have any dependencies yet, but [it will soon](#inject-message-service).
The `@Injectable()` decorator accepts a metadata object for the service, the same way the `@Component()` decorator did for your component classes.
### Get hero data
The `HeroService` could get hero data from anywhere&mdash;a web service, local storage, or a mock data source.
Removing data access from components means you can change your mind about the implementation anytime, without touching any components.
They don't know how the service works.
The implementation in _this_ tutorial will continue to deliver _mock heroes_.
Import the `Hero` and `HEROES`.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="import-heroes">
</code-example>
Add a `getHeroes` method to return the _mock heroes_.
<code-example path="toh-pt4/src/app/hero.service.1.ts" header="src/app/hero.service.ts" region="getHeroes">
</code-example>
{@a provide}
## Provide the `HeroService`
You must make the `HeroService` available to the dependency injection system
before Angular can _inject_ it into the `HeroesComponent` by registering a _provider_. A provider is something that can create or deliver a service; in this case, it instantiates the `HeroService` class to provide the service.
To make sure that the `HeroService` can provide this service, register it
with the _injector_, which is the object that is responsible for choosing
and injecting the provider where the app requires it.
By default, the Angular CLI command `ng generate service` registers a provider with the _root injector_ for your service by including provider metadata, that is `providedIn: 'root'` in the `@Injectable()` decorator.
```
@Injectable({
providedIn: 'root',
})
```
When you provide the service at the root level, Angular creates a single, shared instance of `HeroService` and injects into any class that asks for it.
Registering the provider in the `@Injectable` metadata also allows Angular to optimize an app by removing the service if it turns out not to be used after all.
<div class="alert is-helpful">
To learn more about providers, see the [Providers section](guide/providers).
To learn more about injectors, see the [Dependency Injection guide](guide/dependency-injection).
</div>
The `HeroService` is now ready to plug into the `HeroesComponent`.
<div class="alert is-important">
This is an interim code sample that will allow you to provide and use the `HeroService`. At this point, the code will differ from the `HeroService` in the ["final code review"](#final-code-review).
</div>
## Update `HeroesComponent`
Open the `HeroesComponent` class file.
Delete the `HEROES` import, because you won't need that anymore.
Import the `HeroService` instead.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import">
</code-example>
Replace the definition of the `heroes` property with a simple declaration.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts" region="heroes">
</code-example>
{@a inject}
### Inject the `HeroService`
Add a private `heroService` parameter of type `HeroService` to the constructor.
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" region="ctor">
</code-example>
The parameter simultaneously defines a private `heroService` property and identifies it as a `HeroService` injection site.
When Angular creates a `HeroesComponent`, the [Dependency Injection](guide/dependency-injection) system
sets the `heroService` parameter to the singleton instance of `HeroService`.
### Add `getHeroes()`
Create a method to retrieve the heroes from the service.
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" region="getHeroes">
</code-example>
{@a oninit}
### Call it in `ngOnInit()`
While you could call `getHeroes()` in the constructor, that's not the best practice.
Reserve the constructor for simple initialization such as wiring constructor parameters to properties.
The constructor shouldn't _do anything_.
It certainly shouldn't call a function that makes HTTP requests to a remote server as a _real_ data service would.
Instead, call `getHeroes()` inside the [*ngOnInit lifecycle hook*](guide/lifecycle-hooks) and
let Angular call `ngOnInit()` at an appropriate time _after_ constructing a `HeroesComponent` instance.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts" region="ng-on-init">
</code-example>
### See it run
After the browser refreshes, the app should run as before,
showing a list of heroes and a hero detail view when you click on a hero name.
## Observable data
The `HeroService.getHeroes()` method has a _synchronous signature_,
which implies that the `HeroService` can fetch heroes synchronously.
The `HeroesComponent` consumes the `getHeroes()` result
as if heroes could be fetched synchronously.
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" region="get-heroes">
</code-example>
This will not work in a real app.
You're getting away with it now because the service currently returns _mock heroes_.
But soon the app will fetch heroes from a remote server,
which is an inherently _asynchronous_ operation.
The `HeroService` must wait for the server to respond,
`getHeroes()` cannot return immediately with hero data,
and the browser will not block while the service waits.
`HeroService.getHeroes()` must have an _asynchronous signature_ of some kind.
In this tutorial, `HeroService.getHeroes()` will return an `Observable`
because it will eventually use the Angular `HttpClient.get` method to fetch the heroes
and [`HttpClient.get()` returns an `Observable`](guide/http).
### Observable `HeroService`
`Observable` is one of the key classes in the [RxJS library](http://reactivex.io/rxjs/).
In a [later tutorial on HTTP](tutorial/toh-pt6), you'll learn that Angular's `HttpClient` methods return RxJS `Observable`s.
In this tutorial, you'll simulate getting data from the server with the RxJS `of()` function.
Open the `HeroService` file and import the `Observable` and `of` symbols from RxJS.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts (Observable imports)" region="import-observable">
</code-example>
Replace the `getHeroes()` method with the following:
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="getHeroes-1"></code-example>
`of(HEROES)` returns an `Observable<Hero[]>` that emits _a single value_, the array of mock heroes.
<div class="alert is-helpful">
In the [HTTP tutorial](tutorial/toh-pt6), you'll call `HttpClient.get<Hero[]>()` which also returns an `Observable<Hero[]>` that emits _a single value_, an array of heroes from the body of the HTTP response.
</div>
### Subscribe in `HeroesComponent`
The `HeroService.getHeroes` method used to return a `Hero[]`.
Now it returns an `Observable<Hero[]>`.
You'll have to adjust to that difference in `HeroesComponent`.
Find the `getHeroes` method and replace it with the following code
(shown side-by-side with the previous version for comparison)
<code-tabs>
<code-pane header="heroes.component.ts (Observable)"
path="toh-pt4/src/app/heroes/heroes.component.ts" region="getHeroes">
</code-pane>
<code-pane header="heroes.component.ts (Original)"
path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="getHeroes">
</code-pane>
</code-tabs>
`Observable.subscribe()` is the critical difference.
The previous version assigns an array of heroes to the component's `heroes` property.
The assignment occurs _synchronously_, as if the server could return heroes instantly
or the browser could freeze the UI while it waited for the server's response.
That _won't work_ when the `HeroService` is actually making requests of a remote server.
The new version waits for the `Observable` to emit the array of heroes&mdash;which
could happen now or several minutes from now.
The `subscribe()` method passes the emitted array to the callback,
which sets the component's `heroes` property.
This asynchronous approach _will work_ when
the `HeroService` requests heroes from the server.
## Show messages
This section guides you through the following:
* adding a `MessagesComponent` that displays app messages at the bottom of the screen
* creating an injectable, app-wide `MessageService` for sending messages to be displayed
* injecting `MessageService` into the `HeroService`
* displaying a message when `HeroService` fetches heroes successfully
### Create `MessagesComponent`
Use the CLI to create the `MessagesComponent`.
<code-example language="sh" class="code-shell">
ng generate component messages
</code-example>
The CLI creates the component files in the `src/app/messages` folder and declares the `MessagesComponent` in `AppModule`.
Modify the `AppComponent` template to display the generated `MessagesComponent`.
<code-example
header = "src/app/app.component.html"
path="toh-pt4/src/app/app.component.html">
</code-example>
You should see the default paragraph from `MessagesComponent` at the bottom of the page.
### Create the `MessageService`
Use the CLI to create the `MessageService` in `src/app`.
<code-example language="sh" class="code-shell">
ng generate service message
</code-example>
Open `MessageService` and replace its contents with the following.
<code-example header = "src/app/message.service.ts" path="toh-pt4/src/app/message.service.ts">
</code-example>
The service exposes its cache of `messages` and two methods: one to `add()` a message to the cache and another to `clear()` the cache.
{@a inject-message-service}
### Inject it into the `HeroService`
In `HeroService`, import the `MessageService`.
<code-example
header = "src/app/hero.service.ts (import MessageService)"
path="toh-pt4/src/app/hero.service.ts" region="import-message-service">
</code-example>
Modify the constructor with a parameter that declares a private `messageService` property.
Angular will inject the singleton `MessageService` into that property
when it creates the `HeroService`.
<code-example
path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="ctor">
</code-example>
<div class="alert is-helpful">
This is a typical "*service-in-service*" scenario:
you inject the `MessageService` into the `HeroService` which is injected into the `HeroesComponent`.
</div>
### Send a message from `HeroService`
Modify the `getHeroes()` method to send a message when the heroes are fetched.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="getHeroes">
</code-example>
### Display the message from `HeroService`
The `MessagesComponent` should display all messages,
including the message sent by the `HeroService` when it fetches heroes.
Open `MessagesComponent` and import the `MessageService`.
<code-example header="src/app/messages/messages.component.ts (import MessageService)" path="toh-pt4/src/app/messages/messages.component.ts" region="import-message-service">
</code-example>
Modify the constructor with a parameter that declares a **public** `messageService` property.
Angular will inject the singleton `MessageService` into that property
when it creates the `MessagesComponent`.
<code-example path="toh-pt4/src/app/messages/messages.component.ts" header="src/app/messages/messages.component.ts" region="ctor">
</code-example>
The `messageService` property **must be public** because you're going to bind to it in the template.
<div class="alert is-important">
Angular only binds to _public_ component properties.
</div>
### Bind to the `MessageService`
Replace the CLI-generated `MessagesComponent` template with the following.
<code-example
header = "src/app/messages/messages.component.html"
path="toh-pt4/src/app/messages/messages.component.html">
</code-example>
This template binds directly to the component's `messageService`.
* The `*ngIf` only displays the messages area if there are messages to show.
* An `*ngFor` presents the list of messages in repeated `<div>` elements.
* An Angular [event binding](guide/event-binding) binds the button's click event
to `MessageService.clear()`.
The messages will look better when you add the private CSS styles to `messages.component.css`
as listed in one of the ["final code review"](#final-code-review) tabs below.
## Add additional messages to hero service
The following example shows how to send and display a message each time the user clicks on
a hero, showing a history of the user's selections. This will be helpful when you get to the
next section on [Routing](tutorial/toh-pt5).
<code-example header="src/app/heroes/heroes.component.ts"
path="toh-pt4/src/app/heroes/heroes.component.ts">
</code-example>
The browser refreshes and the page displays the list of heroes.
Refresh the browser to see the list of heroes, and scroll to the bottom to see the
messages from the HeroService. Each time you click a hero, a new message appears to record
the selection. Use the "clear" button to clear the message history.
{@a final-code-review}
## Final code review
Here are the code files discussed on this page.
<code-tabs>
<code-pane header="src/app/hero.service.ts"
path="toh-pt4/src/app/hero.service.ts">
</code-pane>
<code-pane header="src/app/message.service.ts"
path="toh-pt4/src/app/message.service.ts">
</code-pane>
<code-pane header="src/app/heroes/heroes.component.ts"
path="toh-pt4/src/app/heroes/heroes.component.ts">
</code-pane>
<code-pane header="src/app/messages/messages.component.ts"
path="toh-pt4/src/app/messages/messages.component.ts">
</code-pane>
<code-pane header="src/app/messages/messages.component.html"
path="toh-pt4/src/app/messages/messages.component.html">
</code-pane>
<code-pane header="src/app/messages/messages.component.css"
path="toh-pt4/src/app/messages/messages.component.css">
</code-pane>
<code-pane header="src/app/app.module.ts"
path="toh-pt4/src/app/app.module.ts">
</code-pane>
<code-pane header="src/app/app.component.html"
path="toh-pt4/src/app/app.component.html">
</code-pane>
</code-tabs>
## Summary
* You refactored data access to the `HeroService` class.
* You registered the `HeroService` as the _provider_ of its service at the root level so that it can be injected anywhere in the app.
* You used [Angular Dependency Injection](guide/dependency-injection) to inject it into a component.
* You gave the `HeroService` _get data_ method an asynchronous signature.
* You discovered `Observable` and the RxJS _Observable_ library.
* You used RxJS `of()` to return an observable of mock heroes (`Observable<Hero[]>`).
* The component's `ngOnInit` lifecycle hook calls the `HeroService` method, not the constructor.
* You created a `MessageService` for loosely-coupled communication between classes.
* The `HeroService` injected into a component is created with another injected service,
`MessageService`.

View File

@ -1,87 +1,88 @@
# Add services
# Agregar servicios
The Tour of Heroes `HeroesComponent` is currently getting and displaying fake data.
El `HeroesComponent` de Tour de los Heroes actualmente está obteniendo y mostrando datos simulados.
After the refactoring in this tutorial, `HeroesComponent` will be lean and focused on supporting the view.
It will also be easier to unit-test with a mock service.
Después de la refactorización en este tutorial, `HeroesComponent` será sencillo y se centrará en apoyar la vista.
También será más fácil realizar pruebas unitarias con un servicio simulado.
<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>
## Por qué servicios
## Why services
Los componentes no deberían buscar ni guardar datos directamente y, desde luego, no deberían presentar a sabiendas datos simulados.
Deben centrarse en presentar datos y delegar el acceso a los datos a un servicio.
Components shouldn't fetch or save data directly and they certainly shouldn't knowingly present fake data.
They should focus on presenting data and delegate data access to a service.
En este tutorial, crearás un `HeroService` que todas las clases de aplicación pueden usar para obtener héroes.
En lugar de crear ese servicio con la [palabra clave `new`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new),
confiará en la [*inyección de dependencia*](guide/dependency-injection) de Angular
para inyectarlo en el constructor `HeroesComponent`.
In this tutorial, you'll create a `HeroService` that all application classes can use to get heroes.
Instead of creating that service with the [`new` keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new),
you'll rely on Angular [*dependency injection*](guide/dependency-injection)
to inject it into the `HeroesComponent` constructor.
Los servicios son una excelente manera de compartir información entre clases que no se _conocen entre sí_.
Creará un `MessageService` y lo inyectará en dos lugares.
Services are a great way to share information among classes that _don't know each other_.
You'll create a `MessageService` and inject it in two places.
1. Inject in HeroService, which uses the service to send a message.
2. Inject in MessagesComponent, which displays that message, and also displays the ID
when the user clicks a hero.
1. Inyecte en HeroService, que utiliza el servicio para enviar un mensaje.
2. Inyecte en MessagesComponent, que muestra ese mensaje, y también muestra la ID
cuando el usuario hace clic en un héroe.
## Create the `HeroService`
## Crear el `HeroService`
Using the Angular CLI, create a service called `hero`.
Usando la CLI Angular, cree un servicio llamado `hero`.
<code-example language="sh" class="code-shell">
ng generate service hero
</code-example>
The command generates a skeleton `HeroService` class in `src/app/hero.service.ts` as follows:
Este comando generará un archivo base `HeroService` en `src/app/hero.service.ts` de la siguiente manera:
<code-example path="toh-pt4/src/app/hero.service.1.ts" region="new"
header="src/app/hero.service.ts (new service)"></code-example>
### `@Injectable()` services
### Servicio `@Injectable()`
Notice that the new service imports the Angular `Injectable` symbol and annotates
the class with the `@Injectable()` decorator. This marks the class as one that participates in the _dependency injection system_. The `HeroService` class is going to provide an injectable service, and it can also have its own injected dependencies.
It doesn't have any dependencies yet, but [it will soon](#inject-message-service).
Observe que el símbolo Inyectable de Angular se importa en el archivo generado, anotando la clase como decorador `@Injectable()`.
Esto marca a la clase como participante en el sistema de inyección de dependencia. La clase `HeroService` proporcionará servicios inyectables y puede tener dependencias.
Aún no hay dependencias, [estará pronto](#inject-message-service).
The `@Injectable()` decorator accepts a metadata object for the service, the same way the `@Component()` decorator did for your component classes.
El decorador `@Injectable()` acepta el objeto de metadatos de un servicio de la misma manera que el decorador `@Component()` para las clases de componentes.
### Get hero data
### Obtener datos del héroe
The `HeroService` could get hero data from anywhere&mdash;a web service, local storage, or a mock data source.
Removing data access from components means you can change your mind about the implementation anytime, without touching any components.
They don't know how the service works.
El `HeroService` podría obtener datos de héroes desde cualquier lugar&mdash; un servicio web, almacenamiento local o una fuente de datos simulada.
The implementation in _this_ tutorial will continue to deliver _mock heroes_.
Eliminar el acceso a datos de los componentes significa que puede cambiar de opinión acerca de la implementación en cualquier momento, sin tocar ningún componente.
No saben cómo funciona el servicio.
Import the `Hero` and `HEROES`.
La implementación en este tutorial continuará entregando _héroes simulados_.
Importar `Hero` and `HEROES`.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="import-heroes">
</code-example>
Add a `getHeroes` method to return the _mock heroes_.
Agregue el método `getHeroes` y devuelva los _héroes simulados_.
<code-example path="toh-pt4/src/app/hero.service.1.ts" header="src/app/hero.service.ts" region="getHeroes">
</code-example>
{@a provide}
## Provide the `HeroService`
## Proporcionar el `HeroService`
You must make the `HeroService` available to the dependency injection system
before Angular can _inject_ it into the `HeroesComponent` by registering a _provider_. A provider is something that can create or deliver a service; in this case, it instantiates the `HeroService` class to provide the service.
Debe poner el `HeroService` a disposición del sistema de inyección de dependencias.
antes de que Angular pueda inyectarlo en el 'Componente de héroes' al registrar un proveedor. Un proveedor es algo que puede crear o prestar un servicio; en este caso, crea una instancia de la clase `HeroService` para proporcionar el servicio.
To make sure that the `HeroService` can provide this service, register it
with the _injector_, which is the object that is responsible for choosing
and injecting the provider where the app requires it.
Para asegurarse de que el `HeroService` pueda proporcionar este servicio, regístrelo
con el _inyector_, que es el objeto responsable de elegir
e inyectando el proveedor donde la aplicación lo requiere.
By default, the Angular CLI command `ng generate service` registers a provider with the _root injector_ for your service by including provider metadata, that is `providedIn: 'root'` in the `@Injectable()` decorator.
Por defecto, el comando Angular CLI `ng generate service` registra a un proveedor con el inyector raíz para su servicio al incluir los metadatos del proveedor, que se proporcionan en el decorador `@Injectable() `.
```
@Injectable({
@ -89,320 +90,323 @@ By default, the Angular CLI command `ng generate service` registers a provider w
})
```
When you provide the service at the root level, Angular creates a single, shared instance of `HeroService` and injects into any class that asks for it.
Registering the provider in the `@Injectable` metadata also allows Angular to optimize an app by removing the service if it turns out not to be used after all.
Cuando proporciona el servicio en el nivel raíz, Angular crea una única instancia compartida de `HeroService` e inyecta en cualquier clase que lo solicite.
El registro del proveedor en los metadatos `@Injectable` también le permite a Angular optimizar una aplicación eliminando el servicio si resulta que no se usará después de todo.
<div class="alert is-helpful">
To learn more about providers, see the [Providers section](guide/providers).
To learn more about injectors, see the [Dependency Injection guide](guide/dependency-injection).
Para obtener más información sobre los proveedores, consulte la [Sección de proveedores](guide/providers).
Para obtener más información sobre los inyectores, consulte la [Guía de inyección de dependencia](guide/dependency-injection).
</div>
The `HeroService` is now ready to plug into the `HeroesComponent`.
El `HeroService` ahora está listo para conectarse al `HeroesComponent`.
<div class="alert is-important">
This is an interim code sample that will allow you to provide and use the `HeroService`. At this point, the code will differ from the `HeroService` in the ["final code review"](#final-code-review).
Este es un ejemplo de código provisional que le permitirá proporcionar y usar el `HeroService`. En este punto, el código diferirá del `HeroService` en la [" revisión final del código "](#final-code-review).
</div>
<div class="alert is-helpful">
## Update `HeroesComponent`
Si desea obtener más información sobre _proveedores_, consulte [Proveedores](guide/providers).
Open the `HeroesComponent` class file.
</div>
Delete the `HEROES` import, because you won't need that anymore.
Import the `HeroService` instead.
## Actualizar `HeroesComponent`
Abra el archivo de clase `HeroesComponent`.
Elimine la importación `HEROES`, porque ya no la necesitará.
Importa el `HeroService` en su lugar.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import">
</code-example>
Replace the definition of the `heroes` property with a simple declaration.
Reemplace la definición de la propiedad `heroes` con una simple declaración.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts" region="heroes">
</code-example>
{@a inject}
### Inject the `HeroService`
### Inyectar el `HeroService`
Add a private `heroService` parameter of type `HeroService` to the constructor.
Agregue un parámetro privado `heroService` de tipo `HeroService` al constructor.
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" region="ctor">
</code-example>
The parameter simultaneously defines a private `heroService` property and identifies it as a `HeroService` injection site.
El parámetro define simultáneamente una propiedad privada `heroService` y la identifica como un sitio de inyección `HeroService`.
When Angular creates a `HeroesComponent`, the [Dependency Injection](guide/dependency-injection) system
sets the `heroService` parameter to the singleton instance of `HeroService`.
Cuando Angular crea un `HeroesComponent`, el sistema [Inyección de dependencia](guide/dependency-injection) establece el parámetro `heroService` en la instancia única de `HeroService`.
### Add `getHeroes()`
### Añadir `getHeroes()`
Create a method to retrieve the heroes from the service.
Crea un método para recuperar a los héroes del servicio
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" region="getHeroes">
</code-example>
{@a oninit}
### Call it in `ngOnInit()`
### Llamarlo en `ngOnInit()`
While you could call `getHeroes()` in the constructor, that's not the best practice.
Si bien podría llamar a `getHeroes()` en el constructor, esa no es la mejor práctica.
Reserve the constructor for simple initialization such as wiring constructor parameters to properties.
The constructor shouldn't _do anything_.
It certainly shouldn't call a function that makes HTTP requests to a remote server as a _real_ data service would.
Reserve el constructor para una inicialización simple, como conectar los parámetros del constructor a las propiedades.
El constructor no debe _hacer nada_.
Ciertamente no debería llamar a una función que realiza solicitudes HTTP a un servidor remoto como lo haría un servicio de datos _real_.
Instead, call `getHeroes()` inside the [*ngOnInit lifecycle hook*](guide/lifecycle-hooks) and
let Angular call `ngOnInit()` at an appropriate time _after_ constructing a `HeroesComponent` instance.
En su lugar, llame a `getHeroes()` dentro del [*ngOnInit lifecycle hook*](guide/lifecycle-hooks) (gancho del ciclo de vida) y
deje que Angular llame a `ngOnInit()` en el momento apropiado _después_ de construir una instancia de `HeroesComponent`.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts" region="ng-on-init">
</code-example>
### See it run
### Verlo correr
After the browser refreshes, the app should run as before,
showing a list of heroes and a hero detail view when you click on a hero name.
Después de que el navegador se actualice, la aplicación debería ejecutarse como antes,
mostrando una lista de héroes y una vista detallada de héroe cuando haces clic en el nombre de un héroe.
## Observable data
## Datos observables
The `HeroService.getHeroes()` method has a _synchronous signature_,
which implies that the `HeroService` can fetch heroes synchronously.
The `HeroesComponent` consumes the `getHeroes()` result
as if heroes could be fetched synchronously.
El método `HeroService.getHeroes()` tiene una firma sincrónica,
lo que implica que el `HeroService` puede buscar héroes sincrónicamente.
El `HeroesComponent` consume el resultado `getHeroes()`
como si los héroes pudieran ser recuperados sincrónicamente.
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" region="get-heroes">
</code-example>
This will not work in a real app.
You're getting away with it now because the service currently returns _mock heroes_.
But soon the app will fetch heroes from a remote server,
which is an inherently _asynchronous_ operation.
Esto no funcionará en una aplicación real.
Ahora te saldrás con la tuya porque el servicio actualmente devuelve _héroes simulados_.
Pero pronto la aplicación buscará héroes de un servidor remoto,
que es una operación inherentemente _asincrónica_.
The `HeroService` must wait for the server to respond,
`getHeroes()` cannot return immediately with hero data,
and the browser will not block while the service waits.
El `HeroService` debe esperar a que el servidor responda,
`getHeroes()` no puede regresar inmediatamente con los datos del héroe,
y el navegador no se bloqueará mientras el servicio espere.
`HeroService.getHeroes()` must have an _asynchronous signature_ of some kind.
`HeroService.getHeroes()` debe tener una firma asíncrona de algún tipo.
In this tutorial, `HeroService.getHeroes()` will return an `Observable`
because it will eventually use the Angular `HttpClient.get` method to fetch the heroes
and [`HttpClient.get()` returns an `Observable`](guide/http).
En este tutorial, `HeroService.getHeroes()` devolverá un `Observable`
porque eventualmente usará el método angular `HttpClient.get` para buscar a los héroes y [`HttpClient.get()` devuelve un `Observable`](guide/http).
### Observable `HeroService`
`Observable` is one of the key classes in the [RxJS library](http://reactivex.io/rxjs/).
`Observable` es una de las clases clave en la [biblioteca RxJS] (http://reactivex.io/rxjs/).
In a [later tutorial on HTTP](tutorial/toh-pt6), you'll learn that Angular's `HttpClient` methods return RxJS `Observable`s.
In this tutorial, you'll simulate getting data from the server with the RxJS `of()` function.
En un [tutorial posterior sobre HTTP](tutorial/toh-pt6), aprenderá que los métodos `HttpClient` de Angular devuelven RxJS `Observable`s.
En este tutorial, simulará obtener datos del servidor con la función RxJS `of()`.
Open the `HeroService` file and import the `Observable` and `of` symbols from RxJS.
Abra el archivo `HeroService` e importe los símbolos `Observable` y `of` de RxJS.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts (Observable imports)" region="import-observable">
</code-example>
Replace the `getHeroes()` method with the following:
Reemplace el método `getHeroes()` con lo siguiente:
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="getHeroes-1"></code-example>
`of(HEROES)` returns an `Observable<Hero[]>` that emits _a single value_, the array of mock heroes.
`of (HEROES)` devuelve un `Observable <Hero[]>` que emite _un valor único_, el conjunto de héroes simulados.
<div class="alert is-helpful">
<div class="l-sub-section">
In the [HTTP tutorial](tutorial/toh-pt6), you'll call `HttpClient.get<Hero[]>()` which also returns an `Observable<Hero[]>` that emits _a single value_, an array of heroes from the body of the HTTP response.
En el [tutorial HTTP](tutorial/toh-pt6), llamará a `HttpClient.get <Hero[]>()` que también devuelve un `Observable <Hero[]>` que emite _un valor único_, una matriz de héroes del cuerpo de la respuesta HTTP.
</div>
### Subscribe in `HeroesComponent`
### Suscríbirse en `HeroesComponent`
The `HeroService.getHeroes` method used to return a `Hero[]`.
Now it returns an `Observable<Hero[]>`.
El método `HeroService.getHeroes` utilizado para devolver un `Hero[]`.
Ahora devuelve un `Observable <Hero[]>`.
You'll have to adjust to that difference in `HeroesComponent`.
Tendrás que ajustarte a esa diferencia en `HeroesComponent`.
Find the `getHeroes` method and replace it with the following code
(shown side-by-side with the previous version for comparison)
Encuentre el método `getHeroes` y reemplácelo con el siguiente código
(Al lado de la versión anterior para comparar)
<code-tabs>
<code-pane header="heroes.component.ts (Observable)"
<code-pane header="heroes.component.ts (Observable)"
path="toh-pt4/src/app/heroes/heroes.component.ts" region="getHeroes">
</code-pane>
<code-pane header="heroes.component.ts (Original)"
<code-pane header="heroes.component.ts (Original)"
path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="getHeroes">
</code-pane>
</code-tabs>
`Observable.subscribe()` is the critical difference.
`Observable.subscribe()` es la diferencia crítica.
The previous version assigns an array of heroes to the component's `heroes` property.
The assignment occurs _synchronously_, as if the server could return heroes instantly
or the browser could freeze the UI while it waited for the server's response.
La versión anterior asigna una variedad de héroes a la propiedad 'heroes' del componente.
La asignación ocurre _sincrónicamente_, como si el servidor pudiera devolver héroes al instante
o el navegador podría congelar la interfaz de usuario mientras esperaba la respuesta del servidor.
That _won't work_ when the `HeroService` is actually making requests of a remote server.
Eso _no funcionará_ cuando el `HeroService` realmente está haciendo solicitudes a un servidor remoto.
The new version waits for the `Observable` to emit the array of heroes&mdash;which
could happen now or several minutes from now.
The `subscribe()` method passes the emitted array to the callback,
which sets the component's `heroes` property.
La nueva versión espera a que el 'Observable' emita una serie de héroes,&mdash;
que podría suceder ahora o varios minutos a partir de ahora.
El método `subscribe()` pasa el arreglo emitida a la devolución de llamada,
que establece la propiedad 'heroes' del componente.
This asynchronous approach _will work_ when
the `HeroService` requests heroes from the server.
Este enfoque asincrónico funcionará cuando
el `HeroService` solicite héroes del servidor.
## Show messages
## Mostrar mensajes
This section guides you through the following:
Esta sección lo guía a través de lo siguiente:
* adding a `MessagesComponent` that displays app messages at the bottom of the screen
* creating an injectable, app-wide `MessageService` for sending messages to be displayed
* injecting `MessageService` into the `HeroService`
* displaying a message when `HeroService` fetches heroes successfully
* agregando un `MessagesComponent` que muestra los mensajes de la aplicación en la parte inferior de la pantalla
* crear un `MessageService` inyectable para toda la aplicación para enviar mensajes que se mostrarán
* inyectando `MessageService` en el `HeroService`
* mostrando un mensaje cuando `HeroService` busca héroes con éxito
### Create `MessagesComponent`
Use the CLI to create the `MessagesComponent`.
### Crear `MessagesComponent`
Use la CLI para crear el `MessagesComponent`.
<code-example language="sh" class="code-shell">
ng generate component messages
</code-example>
The CLI creates the component files in the `src/app/messages` folder and declares the `MessagesComponent` in `AppModule`.
Modify the `AppComponent` template to display the generated `MessagesComponent`.
La CLI crea los archivos componentes en la carpeta `src/app/messages` y declara el `MessagesComponent` en `AppModule`.
Modifique la plantilla `AppComponent` para mostrar el `MessagesComponent` generado.
<code-example
header = "src/app/app.component.html"
path="toh-pt4/src/app/app.component.html">
</code-example>
You should see the default paragraph from `MessagesComponent` at the bottom of the page.
Debería ver el párrafo predeterminado de `MessagesComponent` en la parte inferior de la página.
### Create the `MessageService`
### Crear el `MessageService`
Use the CLI to create the `MessageService` in `src/app`.
Use la CLI para crear el `MessageService` en `src/app`.
<code-example language="sh" class="code-shell">
ng generate service message
</code-example>
Open `MessageService` and replace its contents with the following.
Abra `MessageService` y reemplace su contenido con lo siguiente.
<code-example header = "src/app/message.service.ts" path="toh-pt4/src/app/message.service.ts">
</code-example>
The service exposes its cache of `messages` and two methods: one to `add()` a message to the cache and another to `clear()` the cache.
El servicio expone su caché de `mensajes` y dos métodos: uno para `agregar()` un mensaje al caché y otro para `borrar()` el caché.
{@a inject-message-service}
### Inject it into the `HeroService`
### Inyectar en el `HeroService`
En `HeroService`, importe el `MessageService`.
In `HeroService`, import the `MessageService`.
<code-example
header = "src/app/hero.service.ts (import MessageService)"
path="toh-pt4/src/app/hero.service.ts" region="import-message-service">
</code-example>
Modify the constructor with a parameter that declares a private `messageService` property.
Angular will inject the singleton `MessageService` into that property
when it creates the `HeroService`.
Modifique el constructor con un parámetro que declare una propiedad privada `messageService`.
Angular inyectará el singleton `MessageService` en esa propiedad
cuando crea el `HeroService`.
<code-example
path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="ctor">
</code-example>
<div class="alert is-helpful">
<div class="l-sub-section">
This is a typical "*service-in-service*" scenario:
you inject the `MessageService` into the `HeroService` which is injected into the `HeroesComponent`.
Este es un escenario típico de "*servicio en servicio*":
inyecta el `MessageService` en el `HeroService` que se inyecta en el `HeroesComponent`.
</div>
### Send a message from `HeroService`
### Enviar un mensaje desde `HeroService`
Modify the `getHeroes()` method to send a message when the heroes are fetched.
Modifique el método `getHeroes()` para enviar un mensaje cuando se busquen los héroes.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="getHeroes">
</code-example>
### Display the message from `HeroService`
### Mostrar el mensaje de `HeroService`
The `MessagesComponent` should display all messages,
including the message sent by the `HeroService` when it fetches heroes.
El `MessagesComponent` debería mostrar todos los mensajes,
incluido el mensaje enviado por el `HeroService` cuando busca héroes.
Open `MessagesComponent` and import the `MessageService`.
Abra `MessagesComponent` e importe el `MessageService`
<code-example header="src/app/messages/messages.component.ts (import MessageService)" path="toh-pt4/src/app/messages/messages.component.ts" region="import-message-service">
</code-example>
Modify the constructor with a parameter that declares a **public** `messageService` property.
Angular will inject the singleton `MessageService` into that property
when it creates the `MessagesComponent`.
Modifique el constructor con un parámetro que declare una propiedad `messageService` **publica**.
Angular inyectará el único `MessageService` en esa propiedad
cuando crea el `MessagesComponent`.
<code-example path="toh-pt4/src/app/messages/messages.component.ts" header="src/app/messages/messages.component.ts" region="ctor">
</code-example>
The `messageService` property **must be public** because you're going to bind to it in the template.
La propiedad `messageService` **debe ser pública** porque la vinculará en la plantilla.
<div class="alert is-important">
Angular only binds to _public_ component properties.
Angular solo se une a las propiedades _publicas_ del componente .
</div>
### Bind to the `MessageService`
Replace the CLI-generated `MessagesComponent` template with the following.
### Enlazar al `MessageService`
Reemplace la plantilla `MessagesComponent` generada por CLI con lo siguiente.
 
<code-example
header = "src/app/messages/messages.component.html"
path="toh-pt4/src/app/messages/messages.component.html">
</code-example>
This template binds directly to the component's `messageService`.
Esta plantilla se une directamente al componente `messageService` del componente.
* The `*ngIf` only displays the messages area if there are messages to show.
* `*NgIf` solo muestra el área de mensajes si hay mensajes para mostrar.
* An `*ngFor` presents the list of messages in repeated `<div>` elements.
* Un `*ngFor` presenta la lista de mensajes en elementos repetidos` <div> `.
* An Angular [event binding](guide/event-binding) binds the button's click event
to `MessageService.clear()`.
* Un [enlace de evento](guide/template-syntax) en angular une el evento de clic del botón
a `MessageService.clear ()`.
The messages will look better when you add the private CSS styles to `messages.component.css`
as listed in one of the ["final code review"](#final-code-review) tabs below.
Los mensajes se verán mejor cuando agregue los estilos CSS privados a `messages.component.css`
como se indica en una de las pestañas ["revisión de código final"](#final-code-review) a continuación.
## Add additional messages to hero service
## Agregar mensajes adicionales al servicio de héroe
The following example shows how to send and display a message each time the user clicks on
a hero, showing a history of the user's selections. This will be helpful when you get to the
next section on [Routing](tutorial/toh-pt5).
El siguiente ejemplo muestra cómo enviar y mostrar un mensaje cada vez que el usuario hace clic en
un héroe, que muestra un historial de las selecciones del usuario. Esto será útil cuando llegues a
siguiente sección sobre [Enrutamiento](tutorial/toh-pt5).
<code-example header="src/app/heroes/heroes.component.ts"
path="toh-pt4/src/app/heroes/heroes.component.ts">
</code-example>
The browser refreshes and the page displays the list of heroes.
Refresh the browser to see the list of heroes, and scroll to the bottom to see the
messages from the HeroService. Each time you click a hero, a new message appears to record
the selection. Use the "clear" button to clear the message history.
El navegador se actualizará y la página mostrará la lista de héroes.
Actualiza el navegador para ver la lista de héroes y desplázate hacia abajo para ver
mensajes del HeroService. Cada vez que haces clic en un héroe, aparece un nuevo mensaje para grabar
la selección. Use el botón "borrar" para borrar el historial de mensajes.
{@a final-code-review}
## Final code review
## Revisión final del código
Here are the code files discussed on this page.
Aquí están los archivos de código discutidos en esta página.
<code-tabs>
<code-pane header="src/app/hero.service.ts"
<code-pane header="src/app/hero.service.ts"
path="toh-pt4/src/app/hero.service.ts">
</code-pane>
<code-pane header="src/app/message.service.ts"
<code-pane header="src/app/message.service.ts"
path="toh-pt4/src/app/message.service.ts">
</code-pane>
@ -432,15 +436,16 @@ Here are the code files discussed on this page.
</code-tabs>
## Summary
## Resumen
* You refactored data access to the `HeroService` class.
* You registered the `HeroService` as the _provider_ of its service at the root level so that it can be injected anywhere in the app.
* You used [Angular Dependency Injection](guide/dependency-injection) to inject it into a component.
* You gave the `HeroService` _get data_ method an asynchronous signature.
* You discovered `Observable` and the RxJS _Observable_ library.
* You used RxJS `of()` to return an observable of mock heroes (`Observable<Hero[]>`).
* The component's `ngOnInit` lifecycle hook calls the `HeroService` method, not the constructor.
* You created a `MessageService` for loosely-coupled communication between classes.
* The `HeroService` injected into a component is created with another injected service,
`MessageService`.
* Refactorizó el acceso a datos a la clase `HeroService`.
* Registro el `HeroService` como el _proveedor_ de su servicio en el nivel raíz para que pueda inyectarse en cualquier lugar de la aplicación.
* Usó la [Inyección de dependencia angular](guide/dependency-injection) para inyectarlo en un componente.
* Le dio al `HeroService` el método _get data_ una firma asincrónica.
* Descubrio `Observable` y la biblioteca RxJS _Observable_.
* Usó RxJS `of ()` para devolver un observable de héroes simulados (`Observable <Hero []>`).
* El lifecycle hook (gancho del ciclo de vida) `ngOnInit` del componente llama al método `HeroService`, no al constructor.
* Creó un `MessageService` para una comunicación débilmente acoplada entre clases.
* El `HeroService` inyectado en un componente se crea con otro servicio inyectado,
`MessageService`.