diff --git a/public/docs/ts/latest/cookbook/dependency-injection.jade b/public/docs/ts/latest/cookbook/dependency-injection.jade index cd4850dc..948802f5 100644 --- a/public/docs/ts/latest/cookbook/dependency-injection.jade +++ b/public/docs/ts/latest/cookbook/dependency-injection.jade @@ -4,49 +4,80 @@ include ../_util-fns Dependency Injection is a powerful pattern for managing code dependencies. In this cookbook we will explore many of the features of Dependency Injection (DI) in Angular. + La inyeccion de dependencias es un poderoso patrón para la gestión de dependencias de código. + En este cookbook se explorarán muchas de las características de la Inyección de dependencias (DI) en Angular. + :marked ## Table of contents + + ## Tabla de contenidos [Application-wide dependencies](#app-wide-dependencies) + [Dependiencias en toda la aplicación](#app-wide-dependencies) [External module configuration](#external-module-configuration) + [Configuración del módulo externo](#external-module-configuration) [*@Injectable* and nested service dependencies](#nested-dependencies) + [*@Injectable* y servicios de dependencias anidados](#nested-dependencies) [Limit service scope to a component subtree](#service-scope) + [Limitar el alcance del servicio a un subárbol componente](#service-scope) [Multiple service instances (sandboxing)](#multiple-service-instances) + [Instancias de servicio multiples (sandboxing)](#multiple-service-instances) [Qualify dependency lookup with *@Optional* and *@Host*](#qualify-dependency-lookup) + [Calificar las operaciones de búsqueda con dependencia con *@Optional* y *@Host*](#qualify-dependency-lookup) [Inject the component's DOM element](#component-element) + [Inyectar los componentes al elmento DOM](#component-element) [Define dependencies with providers](#providers) + [Definir dependencias con proveedores](#providers) * [The *provide* object literal](#provide) + * [El objeto *proveedor* literalmente](#provide) * [useValue - the *value provider*](#usevalue) + * [useValue - el *valor del proveedor*](#usevalue) * [useClass - the *class provider*](#useclass) + * [useClass - la *clase proveedor*](#useclass) * [useExisting - the *alias provider*](#useexisting) + * [useExisting - el *alias del proveedor*](#useexisting) * [useFactory - the *factory provider*](#usefactory) + * [useFactory - la *fabrica del proveedor*](#usefactory) [Provider token alternatives](#tokens) + [Alternativas del token proveedor](#tokens) * [class-interface](#class-interface) + * [clasw-interfaz](#class-interface) * [OpaqueToken](#opaque-token) [Inject into a derived class](#di-inheritance) + [Inyectar una clase derivaba](#di-inheritance) [Find a parent component by injection](#find-parent) + [Encontrar un componente padre mediante la inyección](#find-parent) * [Find parent with a known component type](#known-parent) + * [Encontrar al padre con un tipo de componete conocido](#known-parent) * [Cannot find a parent by its base class](#base-parent) + * [No puede encontrar un padre mediante su clase base](#base-parent) * [Find a parent by its class-interface](#class-interface-parent) + * [Encontrar un padre por su clase-interfaz](#class-interface-parent) * [Find a parent in a tree of parents (*@SkipSelf*)](#parent-tree) + * [Encontrar un padre en un árbol de padres] (*@SkipSelf*)](#parent-tree) * [A *provideParent* helper function](#provideparent) + * [La función auxiliar *provideParent*](#provideparent) [Break circularities with a forward class reference (*forwardRef*)](#forwardref) + [Romper la circularidad con una referencia de clase hacia adelante (*forwardRef*)](#forwardref) :marked **See the ** of the code supporting this cookbook. + + **Ver el ejemplo ** + del código de apoyo en este cookbook. .l-main-section @@ -55,23 +86,41 @@ include ../_util-fns ## Application-wide dependencies Register providers for dependencies used throughout the application in the root application component, `AppComponent`. + ## Dependencias en toda la aplicación + Registrar proveedores de dependencias utilizadas en toda la aplicacion en el componente raíz, `AppComponent`. + In the following example, we import and register several services (the `LoggerService`, `UserContext`, and the `UserService`) in the `@Component` metadata `providers` array. + + En el siguiente ejemplo, se importan y registran varios servicios + (`LoggerService`, `UserContext`, y `UserService`) + en los metadatos del `@Component` y en el arreglo `providers`. +makeExample('cb-dependency-injection/ts/app/app.component.ts','import-services','app/app.component.ts (excerpt)')(format='.') :marked All of these services are implemented as classes. Service classes can act as their own providers which is why listing them in the `providers` array is all the registration we need. + + Todos estos servicios estan implementados como clases. + Las clases de servicio no pueden actuar como sus propios proveedores es por eso que se listan en el arreglo `providers` + es todo el registro que se necesita. .l-sub-section :marked A *provider* is something that can create or deliver a service. Angular creates a service instance from a class provider by "new-ing" it. Learn more about providers [below](#providers). + + Un *proveedor* es algo que puede crear o entregar un servicio. + Angular crea una instancia de un servicio desde la clase proveedor mediante "new-ing". + Aprenda mas sobre los proveedores [abajo](#providers). :marked Now that we've registered these services, Angular can inject them into the constructor of *any* component or service, *anywhere* in the application. + + Ahora que ya se registraron esos servicios, + Angular puede inyectarlos dentro del constructor de *cualquier* componente o servicio, *en cualquier lugar* de la aplicación. +makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','ctor','app/hero-bios.component.ts (component constructor injection)')(format='.') +makeExample('cb-dependency-injection/ts/app/user-context.service.ts','ctor','app/user-context.service.ts (service constructor injection)')(format='.') @@ -80,15 +129,26 @@ include ../_util-fns .l-main-section :marked ## External module configuration + + ## Configuración del módulo externo. We often register providers in the `NgModule` rather than in the root application component. + A menudo se registra a los proveedores en el `NgModule` en lugar de en el componente raíz de la aplicación. + We do this when (a) we expect the service to be injectable everywhere or (b) we must configure another application global service _before it starts_. + Esto se hace con la intención de que (a) el servicio pueda ser inyectado en todos lados. + o (b) hay que configurar otro servicio de aplicación global _antes de que se ejecute_. + We see an example of the second case here, where we configure the Component Router with a non-default [location strategy](../guide/router.html#location-strategy) by listing its provider in the `providers` list of the `AppModule`. + Se verá un ejemplo del segundo caso aquí, cuando se configura el Componente Raíz con una + [estrategia de localización](../guide/router.html#location-strategy) haciendo una lista de sus proveedores + en la lista `providers` de el módulo `AppModule`. + +makeExample('cb-dependency-injection/ts/app/app.module.ts','providers','app/app.module.ts (providers)')(format='.') a(id="injectable") @@ -100,17 +160,31 @@ a(id="nested-dependencies") It shouldn't care. It's the dependency injection's job to create and cache that service. + ## *@Injectable* y dependencias de servicio anidadas + El consumidor de un servicio inyectado no sabe como crear ese servicio. + Y no debe preocuparse por ello. + Es trabajo de la inyección de dependencias crear y recibir ese servicio. + Sometimes a service depends on other services ... which may depend on yet other services. Resolving these nested dependencies in the correct order is also the framework's job. At each step, the consumer of dependencies simply declares what it requires in its constructor and the framework takes over. + A veces un servicio depende de otros servicios ... que a su vez pueden de otros servicios. + Resolver esta dependencia anidada en el orden correcto es también trabajo del framework. + En cada paso, el consumidor de dependencias simplemente declara lo que se requiere en su constructor y el framework se hace cargo. + For example, we inject both the `LoggerService` and the `UserContext` in the `AppComponent`. + + Por ejemplo, se inyectan ambos servicios `LoggerService` y `UserContext` en el componente `AppComponent`. +makeExample('cb-dependency-injection/ts/app/app.component.ts','ctor','app/app.component.ts')(format='.') :marked The `UserContext` in turn has dependencies on both the `LoggerService` (again) and a `UserService` that gathers information about a particular user. + La clase `UserContext` a su vez tiene dependencias tanto en el servicio `LoggerService` (de nuevo) y + el `UserService` que extrae información de un usuario en particular. + +makeExample('cb-dependency-injection/ts/app/user-context.service.ts','injectables','user-context.service.ts (injection)')(format='.') :marked @@ -119,74 +193,132 @@ a(id="nested-dependencies") The `UserContextService` needs the `LoggerService`, which the framework already has, and the `UserService`, which it has yet to create. The `UserService` has no dependencies so the dependency injection framework can just `new` one into existence. + Cuando Angular crea el componente`AppComponent`, el framework de inyección de dependencias crea una instancia del servicio `LoggerService` y + empieza a crear el `UserContextService`. + El `UserContextService` necesita al `LoggerService`, que el framework ya tiene, y el `UserService`, el cual todavía tiene que crear. + El `UserService` no tiene dependencias asi que el framework de inyección de dependencias puede solo crear un`nueva` instancia dentro de la existente. + The beauty of dependency injection is that the author of `AppComponent` didn't care about any of this. The author simply declared what was needed in the constructor (`LoggerService` and `UserContextService`) and the framework did the rest. + La belleza de la inyección de dependencias esta en que el autor del `AppComponent` no debe preocuparse por nada de eso. + El autor simplemente declara lo que necesita dentro del constructor (`LoggerService` y `UserContextService`) y el framework hace el resto. + Once all the dependencies are in place, the `AppComponent` displays the user information: + Una vez que todas las dependencias estan situadas, el `AppComponent` despliega la información del usuario: figure.image-display img(src="/resources/images/cookbooks/dependency-injection/logged-in-user.png" alt="Logged In User") :marked ### *@Injectable()* Notice the `@Injectable()`decorator on the `UserContextService` class. + + Notese el decorador`@Injectable()` en la clase `UserContextService`. +makeExample('cb-dependency-injection/ts/app/user-context.service.ts','injectable','user-context.service.ts (@Injectable)')(format='.') :marked That decorator makes it possible for Angular to identify the types of its two dependencies, `LoggerService` and `UserService`. + Ese decorador hace posible para Angular identificar los tipos de sus dos dependencias, `LoggerService` y `UserService`. + Technically, the `@Injectable()`decorator is only _required_ for a service class that has _its own dependencies_. The `LoggerService` doesn't depend on anything. The logger would work if we omitted `@Injectable()` and the generated code would be slightly smaller. + Técnicamente, el decorador `@Injectable()`es solo necesario en la clase del servicio que tenga _sus propias dependencias_. + El servicio `LoggerService` no depende de nada. El logger debe funcionar incluso si se omite el decorador `@Injectable()` + y el código generado debe ser ligeramente mas pequeño. + But the service would break the moment we gave it a dependency and we'd have to go back and and add `@Injectable()` to fix it. We add `@Injectable()` from the start for the sake of consistency and to avoid future pain. + + Pero el servicio debe fallar en el momento en que se le da una dependencias y se debe volver atrás y + agregar el decorador `@Injectable()` para arreglarlo. Se añade `@Injectable()` desde el inicio para tener una coherencia en el código y evitar problemas futuros. .alert.is-helpful :marked Although we recommend applying `@Injectable` to all service classes, do not feel bound by it. Some developers prefer to add it only where needed and that's a reasonable policy too. + + Aunque se recomienda incluir el decorador `@Injectable` a todas las clases servicio, no se sienta obligado a aplicarlo. + Algunos desarrolladores prefieren añadirlo sólo donde lo necesitan y esa es una política razonable también. + .l-sub-section :marked The `AppComponent` class had two dependencies as well but no `@Injectable()`. It didn't need `@Injectable()` because that component class has the `@Component` decorator. In Angular with TypeScript, a *single* decorator — *any* decorator — is sufficient to identify dependency types. - + + La clase `AppComponent`tenía dos dependencias tambiém pero no el decorador `@Injectable()`. + No necesita el `@Injectable()` porque esta clase componente tiene en decorador `@Component`. + En Angular con TypeScript, un decorador *independiente* — *cualquier* decorador — es suficiente para identificar los tipos de dependencia. .l-main-section :marked ## Limit service scope to a component subtree + ## Limitar el alcance del servicio a un subárbol componente + All injected service dependencies are singletons meaning that, for a given dependency injector ("injector"), there is only one instance of service. + Todas las dependencias de servicio inyectados son únicos en el sentido de que, + para una inyección de dependencia dada ("inyector"), hay sólo una instancia de ese servicio. + But an Angular application has multiple dependency injectors, arranged in a tree hierarchy that parallels the component tree. So a particular service can be *provided* (and created) at any component level and multiple times if provided in multiple components. + Pero una aplicación de Angular tiene multiples dependencias, organizadas en una jerarquía de árbol que es paralelo al árbol de componentes. + By default, a service dependency provided in one component is visible to all of its child components and Angular injects the same service instance into all child components that ask for that service. + Por defecto, una dependencia de servicio provista en un componente es visible para todos sus componentes hijos y + Angular inyecta la misma instancia del servicio dentro de todos los componentes hijos que solicitan ese servicio. + Accordingly, dependencies provided in the root `AppComponent` can be injected into *any* component *anywhere* in the application. + En consecuencia, las dependencias provistas en el componente raíz `AppComponent` pueden ser inyectadas en *cualquier* componente en *cualquier lugar* de la aplicación. + That isn't always desirable. Sometimes we want to restrict service availability to a particular region of the application. + Esto no siempre es deseable. + A veces se quiere restringir la disponibilidad de un servicio a una región en particular de la aplicación. + We can limit the scope of an injected service to a *branch* of the application hierarchy by providing that service *at the sub-root component for that branch*. Here we provide the `HeroService` to the `HeroesBaseComponent` by listing it in the `providers` array: + + Puede limitarse el alcance de un servcio inyectado a una *rama* de la jerarquía de la aplicación + proveyendo ese servicio *en el componente de sub - raíz de dicha rama*. + A continuación se provee el servicio `HeroService` al componente `HeroesBaseComponent` incluyendolo en el arreglo `providers`: +makeExample('cb-dependency-injection/ts/app/sorted-heroes.component.ts','injection','app/sorted-heroes.component.ts (HeroesBaseComponent excerpt)') :marked When Angular creates the `HeroesBaseComponent`, it also creates a new instance of `HeroService` that is visible only to the component and its children (if any). + Cuando Angular crea el componente `HeroesBaseComponent`, también crea una nueva instancia del servicio `HeroService` + que es visible sólo en el componente y sus hijos (si cualquiera de ellos lo utiliza). + We could also provide the `HeroService` to a *different* component elsewhere in the application. That would result in a *different* instance of the service, living in a *different* injector. + + También podría proporcinarse el `HeroService` a un componente *diferente* en otros lugares de la aplicación. + Eso resulta en una instancia *diferente* del servicio, contenido en un inyector *diferente*. + + .l-sub-section :marked We examples of such scoped `HeroService` singletons appear throughout the accompanying sample code, including the `HeroBiosComponent`, `HeroOfTheMonthComponent`, and `HeroesBaseComponent`. Each of these components has its own `HeroService` instance managing its own independent collection of heroes. + + Los ejemplos de esa restricción como el servicio `HeroService` aparecen en el código de ejemplo, + incluyendo los componentes `HeroBiosComponent`, `HeroOfTheMonthComponent`, y `HeroesBaseComponent`. + Cada uno de estos componentes tiene su propia instancia del servicio `HeroService` y la gestión de su propia colección de héroes. .l-main-section .alert.is-helpful @@ -195,31 +327,54 @@ figure.image-display This much Dependency Injection knowledge may be all that many Angular developers ever need to build their applications. It doesn't always have to be more complicated. + ## ¡Tome un descanso! + Todo este conocimiento sobre Inyección de Dependencias puede ser todo lo que muchos desarrolladores de Angular + necesitan para hacer sus propias aplicaciones. No siempre tiene que ser tan complicado. + .l-main-section :marked ## Multiple service instances (sandboxing) + ## Varias instancias de servicio (sandboxing) + Sometimes we want multiple instances of a service at *the same level of the component hierarchy*. + A veces se deseea tener varias instancias de un servicio en *el mismo nivel jerárquico del componente*. + A good example is a service that holds state for its companion component instance. We need a separate instance of the service for each component. Each service has its own work-state, isolated from the service-and-state of a different component. We call this *sandboxing* because each service and component instance has its own sandbox to play in. + Un buen ejemplo es un servicio que mantiene el estado de la instancia del componente de su compañero. + Se necesita una instancia del servicio diferente para cada componente. + Cada servicio tiene su propio estado de trabajo, aislado de el servicio-y-estado de un componente diferente. + A esto se le llama *sandboxing* porque cada instancia del servicio y cada instancia del componente tiene su propio sandbox para jugar. + Imagine a `HeroBiosComponent` that presents three instances of the `HeroBioComponent`. + + Imagine un componente `HeroBiosComponent` que tiene tres instancias del componente `HeroBioComponent`. +makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','simple','ap/hero-bios.component.ts') :marked Each `HeroBioComponent` can edit a single hero's biography. A `HeroBioComponent` relies on a `HeroCacheService` to fetch, cache, and perform other persistence operations on that hero. + + Cada `HeroBioComponent` puede editar una biografía en particular de un héroe. +makeExample('cb-dependency-injection/ts/app/hero-cache.service.ts','service','app/hero-cache.service.ts') :marked Clearly the three instances of the `HeroBioComponent` can't share the same `HeroCacheService`. They'd be competing with each other to determine which hero to cache. + Claramente las tres instancias de el componente `HeroBioComponent` no pueden compartir el mismo `HeroCacheService`. + Tendrán que competir entre sí para determinar que héroe tomar. + Each `HeroBioComponent` gets its *own* `HeroCacheService` instance by listing the `HeroCacheService` in its metadata `providers` array. + + Cada `HeroBioComponent` toma su *propia* instancia del servicio `HeroCacheService` + añadiendo el servicio `HeroCacheService` en los metadatos de su arreglo `providers` +makeExample('cb-dependency-injection/ts/app/hero-bio.component.ts','component','app/hero-bio.component.ts') :marked The parent `HeroBiosComponent` binds a value to the `heroId`. @@ -227,8 +382,15 @@ figure.image-display The getter for the `hero` property pulls the cached hero from the service. And the template displays this data-bound property. + El padre `HeroBiosComponent` liga un valor al `heroId`. + El `ngOnInit` pasa ese `id` al servicio que obtiene y almacena al héroe. + El método getter del la propiedad `hero` + Find this example in live code and confirm that the three `HeroBioComponent` instances have their own cached hero data. + + Este ejemplo puede encontrarse en live code + y confirme que el árbol de instancias del componente `HeroBioComponent` tiene sus propios datos del héroe que almacena. figure.image-display img(src="/resources/images/cookbooks/dependency-injection/hero-bios.png" alt="Bios") @@ -239,67 +401,120 @@ a(id="qualify-dependency-lookup") ## Qualify dependency lookup with *@Optional* and *@Host* We learned that dependencies can be registered at any level in the component hierarchy. + ## Calificar las operaciones de búsqueda de dependencia con *@Optional* y *@Host* + Se aprendió que las dependencias pueden ser registradas a cualquier nivel jerárquico del componente. + When a component requests a dependency, Angular starts with that component's injector and walks up the injector tree - until it finds the first suitable provider. Angular throws an error if it can't find the dependency during that walk. + until it finds the first suitable provider. Angular throws an error if it can't find the dependency during that walk. + + Cuando un componente solicita una dependencia, Angular comienza con el inyector de ese componente y recorre el árbol del inyector + hasta que encuentra el primer proveedor adeecuado. Angular lanza un error si no puede encontrar esa dependencia durante el recorrido que hace al árbol. We *want* this behavior most of the time. But sometimes we need to limit the search and/or accommodate a missing dependency. We can modify Angular's search behavior with the `@Host` and `@Optional` qualifying decorators, used individually or together. + Se *quiere* este comportamiento la mayor parte del tiempo. + Pero a veces se necesita limitar la búsqueda y/o tratar de otra forma la falta de una dependencia. + Puede modificarce el comportamiento de la búsqueda de Angular con los decoradores de calificación `@Host`y `@Optional`, + usandolos juntos o por separado. + The `@Optional` decorator tells Angular to continue when it can't find the dependency. Angular sets the injection parameter to `null` instead. + El decorador `@Optional` le indica a Angular que continue aun cuando no pueda encontrar la dependencia. + Entonces Angular le da un valor `null` al parametro del inyector. + The `@Host` decorator stops the upward search at the *host component*. + El decorador `@Host`detiene la busqueda hacia arriba en el *host component*. + The host component is typically the component requesting the dependency. But when this component is projected into a *parent* component, that parent component becomes the host. We look at this second, more interesting case in our next example. + El componente host es comunmente el componente que solicita la dependencia. + Pero cuando este componente esta dentro de un componente *padre*, entonces el componente padre se convierte en el host. + Se verá este caso más interesánte en el siguiente ejemplo. + ### Demonstration The `HeroBiosAndContactsComponent` is a revision of the `HeroBiosComponent` that we looked at [above](#hero-bios-component). + + ### Demostración + El componente `HeroBiosAndContactsComponent` es una revisión del componente `HeroBiosComponent` que se observó [anteriormente](#hero-bios-component). +makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','hero-bios-and-contacts','app/hero-bios.component.ts (HeroBiosAndContactsComponent)') :marked Focus on the template: + Atención en el ejemplo: +makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','template')(format='.') :marked We've inserted a `` element between the `` tags. Angular *projects* (*transcludes*) the corresponding `HeroContactComponent` into the `HeroBioComponent` view, placing it in the `` slot of the `HeroBioComponent` template: + + Se insertó el elemento `` entre las etiquetas ``. + Angular *proyyecta* (*incluye*) el componente correspondiente `HeroContactComponent` dentro de la vista del componente `HeroBioComponent`, + colocándolo en el espacio `` de la plantilla `HeroBioComponent`: +makeExample('cb-dependency-injection/ts/app/hero-bio.component.ts','template','app/hero-bio.component.ts (template)')(format='.') :marked It looks like this, with the hero's telephone number from `HeroContactComponent` projected above the hero description: + + Luce como a continuación se muestra, con el teléfono del héroe de el componente `HeroContactComponent` proyectado sobre la descripción: figure.image-display img(src="/resources/images/cookbooks/dependency-injection/hero-bio-and-content.png" alt="bio and contact") :marked Here's the `HeroContactComponent` which demonstrates the qualifying decorators that we're talking about in this section: + + A continuación está el componente `HeroContactComponent` que muestra los decoradores de calificación justo como se ha hablado de ellos en esta sección: +makeExample('cb-dependency-injection/ts/app/hero-contact.component.ts','component','app/hero-contact.component.ts') :marked Focus on the constructor parameters + + Atención el los parámetros del constructor +makeExample('cb-dependency-injection/ts/app/hero-contact.component.ts','ctor-params','app/hero-contact.component.ts')(format='.') :marked The `@Host()` function decorating the `heroCache` property ensures that we get a reference to the cache service from the parent `HeroBioComponent`. Angular throws if the parent lacks that service, even if a component higher in the component tree happens to have that service. + La función el decorador `@Host()` en la propiedad `heroCache` es asegurar que + se tiene una referencia al servicio desde el componente padre `HeroBioComponent`. + Angular lanza una excepción cuando el padre carece de ese servicio, incluso si un componente de más alto nivel en el árbol tiene ese servicio. + A second `@Host()` function decorates the `loggerService` property. We know the only `LoggerService` instance in the app is provided at the `AppComponent` level. The host `HeroBioComponent` doesn't have its own `LoggerService` provider. + Una segunda función `@Host()` decora la propiedad `loggerService`. + Se conoce que la única instancia del servicio `LoggerService` en la aplicación la provee el `AppComponent`. + El host `HeroBioComponent` no tiene su propio proveeder del servicio `LoggerService`. + Angular would throw an error if we hadn't also decorated the property with the `@Optional()` function. Thanks to `@Optional()`, Angular sets the `loggerService` to null and the rest of the component adapts. + Angular lanzaría un error si no se hubiera decorado la propiedad con la función `@Optional()`. + Gracias a la función `@Optional()`, Angular cambia el valor de `loggerService` a null y el resto del componete se adapta a ese cambio. + .l-sub-section :marked We'll come back to the `elementRef` property shortly. + + Se volvera a la propiedad `elementRef` en breve. :marked Here's the `HeroBiosAndContactsComponent` in action. + + A continuación se encuentra el `HeroBiosAndContactsComponent` en acción. figure.image-display img(src="/resources/images/cookbooks/dependency-injection/hero-bios-and-contacts.png" alt="Bios with contact into") :marked If we comment out the `@Host()` decorator, Angular now walks up the injector ancestor tree until it finds the logger at the `AppComponent` level. The logger logic kicks in and the hero display updates with the gratuitous "!!!", indicating that the logger was found. + + Si se comenta el decorador `@Host()`, Angular recorre en árbol del inyector ancestro + hasta que encuentre el logger en el nivel del `AppComponent`. La lógica del logger entra en acción y la pantalla actualiza la información del héroe + con los signos "!!!", indicado que el logger fue encontrado. figure.image-display img(src="/resources/images/cookbooks/dependency-injection/hero-bio-contact-no-host.png" alt="Without @Host") :marked @@ -307,31 +522,57 @@ figure.image-display the application fails for lack of the required logger at the host component level.
`EXCEPTION: No provider for LoggerService! (HeroContactComponent -> LoggerService)` - + + Por otro lado, si se deja el decorador `@Host()` activo y se comenta `@Optional`, + la aplicación falla por la falta del logger requerido a nivel del componete host. +
+ `EXCEPCIÓN: ¡No se encontro proveedor para el servicio LoggerService! (HeroContactComponent -> LoggerService)` + :marked ## Inject the component's element + ## Inyectar un elemento del componente + On occasion we might need to access a component's corresponding DOM element. Although we strive to avoid it, many visual effects and 3rd party tools (such as jQuery) require DOM access. + En ocasiones puede ser que se necesite acceder al elemento DOM de un componente. + Aunque se hace un esfuerzo para evitarlo,muchos efectos visuales y herramientas de terceros (como jQuery) + requieren de acceso al DOM. + To illustrate, we've written a simplified version of the `HighlightDirective` from the [Attribute Directives](../guide/attribute-directives.html) chapter. + + Para ilustrar esto, se ha escrito una versión simplificada de `HighlightDirective` del + capítulo [Directivas atributo](../guide/attribute-directives.html). +makeExample('cb-dependency-injection/ts/app/highlight.directive.ts','','app/highlight.directive.ts') :marked The directive sets the background to a highlight color when the user mouses over the DOM element to which it is applied. + La directiva resalta el color de fondo cuando el usuario desplaza el mouse sobre el + elemento DOM al que aplique. + Angular set the constructor's `el` parameter to the injected `ElementRef` which is a wrapper around that DOM element. Its `nativeElement` property exposes the DOM element for the directive to manipulate. + Angular cambia el parámetro del constructor `el` al valor que tenga la propiedad inyectada `ElementRef` en cual es + como una evoltura de ese elemento del DOM. + Su propiedad `nativeElement` al elemento DOM para que la directiva pueda manipularlo. + The sample code applies the directive's `myHighlight` attribute to two `
` tags, first without a value (yielding the default color) and then with an assigned color value. + + El código de ejemplo aplica la directiva del atributo `myHighlight` a dos etiquetas `
`, + primero son un valor (poniendo el color por fedecto) y despues con un valor asignando el color. +makeExample('cb-dependency-injection/ts/app/app.component.html','highlight','app/app.component.html (highlight)')(format='.') :marked The following image shows the effect of mousing over the `` tag. + + La siguiente imágen muestra el efecto de desplazar el mouse sobre la etiqueta ``. figure.image-display img(src="/resources/images/cookbooks/dependency-injection/highlight.png" alt="Highlighted bios") :marked @@ -341,55 +582,100 @@ figure.image-display :marked ## Define dependencies with providers + ## Definir dependencias con proveedores + In this section we learn to write providers that deliver dependent services. + En esta sección se aprenderá a escribie proveedores que ofrecen servicios dependientes. + ### Background We get a service from a dependency injector by giving it a ***token***. + ### Previamente + Se tiene un servicio de un inyector de dependencia dándole un ***token***. + We usually let Angular handle this transaction for us by specifying a constructor parameter and its type. The parameter type serves as the injector lookup *token*. Angular passes this token to the injector and assigns the result to the parameter. Here's a typical example: + + Usualmente se deja que Angular maneje esta transacción, especificandole el parámetro del constructor y su tipo. + El tipo de dato del parámetro sirve como el *token* para la búsqueda del inyector. + Angular pasa este token al inyector y asigna el resultado al parámetro. + A continuación hay un ejemplo de esto: +makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','ctor','app/hero-bios.component.ts (component constructor injection)')(format='.') :marked Angular asks the injector for the service associated with the `LoggerService` and and assigns the returned value to the `logger` parameter. + Angular solicita al inyector el servicio asociado con el `LoggerService` y + asigna el valor que le regresa al parámetro `logger`. + Where did the injector get that value? It may already have that value in its internal container. If it doesn't, it may be able to make one with the help of a ***provider***. A *provider* is a recipe for delivering a service associated with a *token*. + + ¿De dónde toma ese valor el inyector? + Puede ser que el inyector ya tenga ese valor en su contenedor interno. + Pero si no es asi, puede hacerlo con la ayuda de un ***proveedor***. + Un *proveedor* es una receta para entregar un servicio con un *token* asociado. .l-sub-section :marked If the injector doesn't have a provider for the requested *token*, it delegates the request to its parent injector, where the process repeats until there are no more injectors. If the search is futile, the injector throws an error ... unless the request was [optional](#optional). + Si el inyector no tiene un proveedor para el *token* solicitado, delega la petición + a su inyector padre, donde se repite este proceso hasta que no hay mas inyectores. + Si la busqúeda es inútil, el inyector lanza un error ... a meos que la solicitud sea [opcional](#optional). + Let's return our attention to providers themselves. + + Volvamos la atención a los proveedores. :marked A new injector has no providers. Angular initializes the injectors it creates with some providers it cares about. We have to register our _own_ application providers manually, usually in the `providers` array of the `Component` or `Directive` metadata: + + Un nuevo inyector no tiene proveedores. + Angular inicializa los inyectores, los crea con algunos proveedores a los que les preocupa. + Debe registrarse los provedoores _propios_ de la aplicación manualmente, + esto se hace generalmente en el arreglo `providers` de los metadatos del `Component` o del `Directive`: + +makeExample('cb-dependency-injection/ts/app/app.component.ts','providers','app/app.component.ts (providers)') :marked ### Defining providers + ### Definiendo a los proveedores + The simple class provider is the most typical by far. We mention the class in the `providers` array and we're done. + + El proveedor de clase simple es la más usual a usar. + Se mencionó la clase en el arreglo `providers` y nada más +makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','class-provider','app/hero-bios.component.ts (class provider)')(format='.') :marked It's that simple because the most common injected service is an instance of a class. But not every dependency can be satisfied by creating a new instance of a class. We need other ways to deliver dependency values and that means we need other ways to specify a provider. + Es así de simple porque el servicio inyectado más común es una instancia de la clase. + Pero no todas las dependencias pueden ser tratatas creando una nueva instancia de la clase. + Se necesitan otras formas para entregar los valores de dependencia y eso significa que se necesitan otras formas de especificar un proveedor. + The `HeroOfTheMonthComponent` example demonstrates many of the alternatives and why we need them. + El ejemplo `HeroOfTheMonthComponent` muestra muchas alternativas y por qué se necesitan cada una de ellas. + figure.image-display img(src="/resources/images/cookbooks/dependency-injection/hero-of-month.png" alt="Hero of the month" width="300px") :marked It's visually simple: a few properties and the output of a logger. The code behind it gives us plenty to talk about. + + Visualmente es simple: solo algunas propiedades y el resultado del logger. Pero el código detrás de esto da mucho que hablar. +makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','hero-of-the-month','hero-of-the-month.component.ts') .l-main-section @@ -397,68 +683,122 @@ a(id='provide') :marked #### The *provide* object literal + ### El objeto *provide* + The `provide` object literal takes a *token* and a *definition object*. The *token* is usually a class but [it doesn't have to be](#tokens). + El objeto `provide` recibe un *token* y una *definición del objeto* + El *token* es generalmente una clase pero [no tiene que serlo necesariamente](#tokens). + The *definition* object has one main property, (e.g. `useValue`) that indicates how the provider should create or return the provided value. + + La *defincición* del objeto tiene una propiedad principal, (por ejemplo `useValue`) que indica como el proveedor + debe crear o regresar el valor provisto. .l-main-section a(id='usevalue') :marked #### useValue - the *value provider* + #### useValue - el *proveedor de valores* + Set the `useValue` property to a ***fixed value*** that the provider can return as the dependency object. + Cambiar la propiedad `useValue` a un ***valor fijo*** que el proveedor pueda devolver como el objeto de dependencia. + Use this technique to provide *runtime configuration constants* such as web-site base addresses and feature flags. We often use a *value provider* in a unit test to replace a production service with a fake or mock. + Se utiliza esta técnica para proporcionar *constantes de configuración en tiempo de ejecución* tales como las direcciones base del sitio Web y las banderas características. + The `HeroOfTheMonthComponent` example has two *value providers*. The first provides an instance of the `Hero` class; the second specifies a literal string resource: + + El ejemplo `HeroOfTheMonthComponent` tiene dos *proveedores de valores* + El primero provee una instancia de la clase `Hero`; + el segundo especifica una literal de tipo string: +makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','use-value')(format='.') :marked The `Hero` provider token is a class which makes sense because the value is a `Hero` and the consumer of the injected hero would want the type information. + El proveedor del token `Hero` es una clase, lo cual tiene sentido porque el varo es un `Hero` + y el consumidor de el héroe inyectado requiere de la información de ese tipo. + The `TITLE` provider token is *not a class*. It's a special kind of provider lookup key called an [OpaqueToken](#opaquetoken). We often use an `OpaqueToken` when the dependency is a simple value like a string, a number, or a function. + El proveedor del token `TITLE` *no es una clase*. + Es un tipo especial de proveedor de clave de búsqueda llamado[OpaqueToken](#opaquetoken). + A menudo se usa un `OpaqueToken` cuando la dependencia es un valor simple como un string, un número, o una función. + The value of a *value provider* must be defined *now*. We can't create the value later. Obviously the title string literal is immediately available. The `someHero` variable in this example was set earlier in the file: + + El valor de un *proveedor de valores* debe definirse *ahora*. No puede crearce el valor más adelante. + Evidentemente la literal title esta disponible inmediatamente. + La variable `someHero` de este ejemplo se estableció anteriormente en el archivo: +makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','some-hero') :marked The other providers create their values *lazily* when they're needed for injection. + + Los otros proveedores crean sus valores *perezosamente* cuando lo necesitan para la inyección. .l-main-section a(id='useclass') :marked #### useClass - the *class provider* + #### useClass - la *clase proveedor* + The `useClass` provider creates and returns new instance of the specified class. + La clase proveedor `useClass` crea y devuelve una nueva instancia de la clase especificada. + Use this technique to ***substitute an alternative implementation*** for a common or default class. The alternative could implement a different strategy, extend the default class, or fake the behavior of the real class in a test case. + Se usa esta técnica para *** sustituir una implementación alternativa*** para una clase en común o por defecto. + Esta alternativa puede emplear una estrategia diferente, estendiendo la clase por defecto, + o simulando el comportamiendo de la clase real en un caso de prueba. + We see two examples in the `HeroOfTheMonthComponent`: + + Pueden verse estos dos ejemplos en el componente `HeroOfTheMonthComponent`: +makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','use-class')(format='.') :marked The first provider is the *de-sugared*, expanded form of the most typical case in which the class to be created (`HeroService`) is also the provider's injection token. We wrote it in this long form to de-mystify the preferred short form. + El primer proveedor es el *de-sugared*, el caso más común en donde + la clase a crear (`HeroService`) tambien es el token para la la inyección del proveedor. + Se escribió de la forma larga para desmitificar la forma corta de hacerlo. + The second provider substitutes the `DateLoggerService` for the `LoggerService`. The `LoggerService` is already registered at the `AppComponent` level. When _this component_ requests the `LoggerService`, it receives the `DateLoggerService` instead. + + El segundo proveedor sustituye el `DateLoggerService` del `LoggerService`. + El servicio `LoggerService` ya está registrado en el `AppComponent`. + Caundo _este componente_ solcita al servicio `LoggerService`, recibe en su lugar a el servicio `DateLoggerService`. .l-sub-section :marked This component and its tree of child components receive the `DateLoggerService` instance. Components outside the tree continue to receive the original `LoggerService` instance. + + Este componente y su árbol de componentes hijos reciben una instancia del servicio `DateLoggerService`. + Los componentes que no están en el árbol continuan recibiendo la instancia original del servicio `LoggerService`. :marked The `DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message: + + El servicio `DateLoggerService` hereda del `LoggerService`; se agrega la fecha /hora actuales a cada mensaje: +makeExample('cb-dependency-injection/ts/app/date-logger.service.ts','date-logger-service','app/date-logger.service.ts')(format='.') .l-main-section @@ -466,25 +806,42 @@ a(id='useexisting') :marked #### useExisting - the *alias provider* + #### useExisting - el *proveedor de alias* + The `useExisting` provider maps one token to another. In effect, the first token is an ***alias*** for the service associated with second token, creating ***two ways to access the same service object***. + + El proveedor `useExisting` mapea de un token a otro. + En efecto, el primer toekn es un ***alias*** para el servicio asociado al segundo token, + creando ***dos formas de acceder al mismo objeto del servicio***. +makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','use-existing') :marked Narrowing an API through an aliasing interface is _one_ important use case for this technique. We're aliasing for that very purpose here. Imagine that the `LoggerService` had a large API (it's actually only three methods and a property). We want to shrink that API surface to just the two members exposed by the `MinimalLogger` [*class-interface*](#class-interface): + + Reducir un API mediante una interfaz alias es _una_ importante aplicacipión para esta técnica. + Se esta dando un alias para ese mismo propósito. + Imagine que el servicio `LoggerService` tiene una API muy extensa (hasta ahora solo cuenta con tres métodos y una propiedad) + Se desea reducir esa API para sólo los dos miembros expuestos por el `MinimalLogger` [*class-interface*](#class-interface): +makeExample('cb-dependency-injection/ts/app/date-logger.service.ts','minimal-logger','app/date-logger.service.ts (MinimalLogger)')(format='.') :marked The constructor's `logger` parameter is typed as `MinimalLogger` so only its two members are visible in TypeScript: + + El parámetro `logger` del constructor está declarado de tipo `MinimalLogger` por lo que sólo sus dos miembros son visibles en TypeScript: figure.image-display img(src="/resources/images/cookbooks/dependency-injection/minimal-logger-intellisense.png" alt="MinimalLogger restricted API") :marked Angular actually sets the `logger` parameter to the injector's full version of the `LoggerService` which happens to be the `DateLoggerService` thanks to the override provider registered previously via `useClass`. The following image, which displays the logging date, confirms the point: + + En realidad Angular fija el parámetro `logger` a la versión completa del inyector del servicio `LoggerService` + el cual pasa a ser el `DateLoggerService` gracias a la anulación del proveedor registrado previamente a través de la clase `useClass`. + La siguiente imágen, se observa este hecho, se muestra la fecha de registro: figure.image-display img(src="/resources/images/cookbooks/dependency-injection/date-logger-entry.png" alt="DateLoggerService entry" width="300px") @@ -493,80 +850,146 @@ a(id='usefactory') :marked #### useFactory - the *factory provider* + #### useFactory - el *proveedor de fabrica* + The `useFactory` provider creates a dependency object by calling a factory function as seen in this example. + + El proveedor `useFactory` crea un objeto de dependencia llamando a una función de fabrica + como se observa en éste ejemplo. +makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','use-factory') :marked Use this technique to ***create a dependency object*** with a factory function whose inputs are some ***combination of injected services and local state***. + Ésta técnica se usa para ***crear un objeto de dependencia*** + con una función de fabrica que cuyas entradas son ***una combinación de servicios inyectados y el estado local***. + The *dependency object* doesn't have to be a class instance. It could be anything. In this example, the *dependency object* is a string of the names of the runners-up to the "Hero of the Month" contest. + + El *objeto de dependencia* no necesariamente es una instancia de la clase. Puede ser cualquier cosa. + En éste ejemplo, el *objeto de dependencia* es una cadena con los nombres de los subcampeones + del concurso "Héroe del mes". The local state is the number `2`, the number of runners-up this component should show. We execute `runnersUpFactory` immediately with `2`. + El estado local es el número `2`, éste componente debe mostrar el número de subcampeones. + Se ejecuta immediatamente el `runnersUpFactory` con el valor `2`. + The `runnersUpFactory` itself isn't the provider factory function. The true provider factory function is the function that `runnersUpFactory` returns. + El `runnersUpFactory` no es en sí la función del proveedor de fabrica. + La verdadera función del proveedor de fabrica es la función que devuelve el `runnersUpFactory`. + + +makeExample('cb-dependency-injection/ts/app/runners-up.ts','factory-synopsis','runners-up.ts (excerpt)')(format='.') :marked That returned function takes a winning `Hero` and a `HeroService` as arguments. + Esa función devuelta toma como argumentos a un `Hero` y un `HeroService`. + Angular supplies these arguments from injected values identified by the two *tokens* in the `deps` array. The two `deps` values are *tokens* that the injector uses to provide these factory function dependencies. + Angular toma éstos argumentos desde los valores inyectados identificados por + los dos *tokens* en el arreglo `deps`. + Los dos valores en el arreglo `deps` son los *tokens* que el inyector utiliza + para proveer estas dependencias de la función de fábrica. + After some undisclosed work, the function returns the string of names and Angular injects it into the `runnersUp` parameter of the `HeroOfTheMonthComponent`. + Despues de un poco de trabajo oculto, la función devuelve la cadena con los nombres + y Angular los inyecta en el `runnersUp` que es el parámetro del componente `HeroOfTheMonthComponent`. + .l-sub-section :marked The function retrieves candidate heroes from the `HeroService`, takes `2` of them to be the runners-up, and returns their concatenated names. Look at the for the full source code. + + La funcion recupera los candidatos a héroes desde el servicio `HeroService`, + toma `2` de ellos para ser los subcampeones, y devuelve la concatenación de sus nombres. + Puede ver el ejemplo + con el código fuente completo. a(id="tokens") .l-main-section :marked ## Provider token alternatives: the *class-interface* and *OpaqueToken* + + ## Proveedor de token alternativo: la *clase-interfaz* y el *OpaqueToken* Angular dependency injection is easiest when the provider *token* is a class that is also the type of the returned dependency object (what we usually call the *service*). + La inyección de dependencias en Angular es más fácil cuando el proveedor de *token* es una clase + porque esa es también el tipo de objeto de dependencia que devuelve (que generalmente llama al *servicio*). + But the token doesn't have to be a class and even when it is a class, it doesn't have to be the same type as the returned object. That's the subject of our next section. + Pero el token no necesariamente es siempre una clase, e incluso cuando lo es, + no tiene que ser del mismo tipo que el objeto devuelto. + Ese es el tema de la próxima sección. + ### class-interface In the previous *Hero of the Month* example, we used the `MinimalLogger` class as the token for a provider of a `LoggerService`. + + ### clase-interfaz + En el ejemplo anterior *Héroe del mes*, se uso la clase `MinimalLogger` + como el token para el proveedor del servicio `LoggerService`. +makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','use-existing') :marked The `MinimalLogger` is an abstract class. + + La clase `MinimalLogger` es abstracta. +makeExample('cb-dependency-injection/ts/app/date-logger.service.ts','minimal-logger')(format='.') :marked We usually inherit from an abstract class. But `LoggerService` doesn't inherit from `MinimalLogger`. *No class* inherits from it. Instead, we use it like an interface. + Usualmente se hereda de una clase abstracta. + Pero el servicio `LoggerService` no hereda de la clase `MinimalLogger`. *Ninguna clase* hereda de ella. + En lugar de eso, se utiliza como una interfaz. + Look again at the declaration for `DateLoggerService` + + Observe de nuevo la declaracion para el `DateLoggerService` +makeExample('cb-dependency-injection/ts/app/date-logger.service.ts','date-logger-service-signature')(format='.') :marked `DateLoggerService` inherits (extends) from `LoggerService`, not `MinimalLogger`. The `DateLoggerService` *implements* `MinimalLogger` as if `MinimalLogger` were an *interface*. + La clase `DateLoggerService` hereda (extiende) de la clase `LoggerService`, no de `MinimalLogger`. + El `DateLoggerService` *implementa* a `MinimalLogger` como si ésta fuera una *interfaz*. + We call a class used in this way a ***class-interface***. The key benefit of a *class-interface* is that we can get the strong-typing of an interface and we can ***use it as a provider token*** in the same manner as a normal class. + A una clase usada de ésta forma se le llama ***clase-interfaz***. + El principal beneficio de una *clase-interfaz* es que puede tenerse el tipado fuerte de una interfaz + y puede ***usarse como un token para el proveedor*** de la misma forma que una clase normal. + A ***class-interface*** should define *only* the members that its consumers are allowed to call. Such a narrowing interface helps decouple the concrete class from its consumers. The `MinimalLogger` defines just two of the `LoggerClass` members. + + Una ***clase-interfaz*** deberia´definir *únicamente* los miembros que sus consumidores pueden llamar. + Dicha interfaz ayuda a desacoplar a la clase en concreto de sus consumidores. + La clase `MinimalLogger` define sólo dos de los miembrso de la clase `LoggerClass`. .l-sub-section :marked @@ -576,35 +999,70 @@ a(id="tokens") They exist only in the TypeScript design space. They disappear after the code is transpiled to JavaScript. + #### Por qué *MinimalLogger* es una clase y no una interfaz. + No puede usarse una interfaz como un token para el proveedor porque + en JavaScript no existen las interfaces. + Sólo existen para TypeScript. + Desaparecen despues de convertir el código a JavaScript. + A provider token must be a real JavaScript object of some kind: a function, an object, a string ... a class. + Un token para el proveedor debe ser un objeto JavaScript de cualquier tipo: + una función, un objeto, una cadena ... una clase. + Using a class as an interface gives us the characteristics of an interface in a JavaScript object. + Usar una clase como interfaz ofrece las caractéristicas de una interfaz en un objeto de JavaScript. + The minimize memory cost, the class should have *no implementation*. The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript: + + Para minimizar el costo de memoria, la clase no debe tener *implementación*. + La clase `MinimalLogger` no esta optimizada, la pre-minificación de JavaScript es: + +makeExample('cb-dependency-injection/ts/app/date-logger.service.ts','minimal-logger-transpiled')(format='.') :marked It never grows larger no matter how many members we add *as long as they are typed but not implemented*. + + Nunca se hace más grande, no importa cuantos miembros se agreguen *siempre y cuando sólo estes declarados y no implementados*. + a(id='opaque-token') :marked ### OpaqueToken + ### OpaqueToken + Dependency objects can be simple values like dates, numbers and strings or shapeless objects like arrays and functions. + Los objetos de dependencia pueden ser valores simplens como fechas, números y cadenas u + objetos como arreglos y funciones. + Such objects don't have application interfaces and therefore aren't well represented by a class. They're better represented by a token that is both unique and symbolic, a JavaScript object that has a friendly name but won't conflict with another token that happens to have the same name. + Estos objetos no tienen intrefacez de aplicación y por lo tanto no están bien representados por una clase. + Se representan mejor con un token, que a la ve es unico y simbólico, + un objeto de JavaScript que tiene un nombre descriptivo no entrarpa en conflicto con + otro token que pueda llegar a tener el mismo nombre. + + The `OpaqueToken` has these characteristics. We encountered them twice in the *Hero of the Month* example, in the *title* value provider and in the *runnersUp* factory provider. + + El `OpaqueToken` tiene éstas características. + Se encuentran dos veces en el ejemplo *Héroe del mes*, + en el valor del proveedor *título* y en el proveedor de fabrica *subcampeones*. +makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','provide-opaque-token')(format='.') :marked We created the `TITLE` token like this: + + Se crea el token `TITLE` de la siguiente forma: +makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','opaque-token')(format='.') @@ -617,9 +1075,18 @@ a(id="di-inheritance") we must re-provide and re-inject them in the derived class and then pass them down to the base class through the constructor. + ## Inyectar en una clase derivada + Hay que tener cuidado al escribir un componente que hereda de otro componene. + Si el componente base tiene dependencias inyectadas, + se debe volver a proveer e inyectar esas dependencias en la clase derivada + y pasarlas a la clase base mediante el constructor. + In this contrived example, `SortedHeroesComponent` inherits from `HeroesBaseComponent` to display a *sorted* list of heroes. + En el siguiente ejemplo, la clase `SortedHeroesComponent` hereda de la clase `HeroesBaseComponent` lo necesario + para mostrar una lista *ordenada* de héroes. + figure.image-display img(src="/resources/images/cookbooks/dependency-injection/sorted-heroes.png" alt="Sorted Heroes") :marked @@ -627,6 +1094,10 @@ figure.image-display It demands its own instance of the `HeroService` to get heroes and displays them in the order they arrive from the database. + La clase `HeroesBaseComponent` podría mantenerse por sí misma. + Solicita su propia instancia de el servicio `HeroService` para obtener a los héroes + y mostrarlos en el orden en el que lleguen desde la basa de datos. + +makeExample('cb-dependency-injection/ts/app/sorted-heroes.component.ts','heroes-base','app/sorted-heroes.component.ts (HeroesBaseComponent)') .l-sub-section :marked @@ -634,7 +1105,13 @@ figure.image-display This rule makes the component safe to construct under test without fear that it will do something dramatic like talk to the server. That's why we call the `HeroService` from within the `ngOnInit` rather than the constructor. + Son preferibles los constructores simples. Éstos hacen un poco más que inicializar variables. + Ésta regla hace que el componente de seguridad para construir bajo prueba sin temor a que hará algo drástico como comunicarse con el servidor. + Esa es la razón para llamar al servicio `HeroService` dentro del método `ngOnInit` en lugar de en el constructor. + We explain the mysterious `afterGetHeroes` below. + + Se explica el misterio del `afterGetHeroes` a continuación. :marked Users want to see the heroes in alphabetical order. Rather than modify the original component, we sub-class it and create a @@ -642,9 +1119,19 @@ figure.image-display The `SortedHeroesComponent` lets the base class fetch the heroes. (we said it was contrived). + Los usuarios quieren ver a los héroes en orden alfabético. + Para lograr ésto, en lugar de modificar el componente original, se crea una sub-clase + `SortedHeroesComponent` que ordene a los héroes antes de mostrarlos. + La clase `SortedHeroesComponent` permite a la clase base buscar a los héroes. + (se dijo que es artificial). + Unfortunately, Angular cannot inject the `HeroService` directly into the base class. We must provide the `HeroService` again for *this* component, then pass it down to the base class inside the constructor. + + Desafortunadamente, Angular no puede inyectar el servicio `HeroService` directamente en la clase base. + Debe proveerse el servicio `HeroService` de nuevo para *éste* componente, + despues pasarlo hacia la clase base dentro del constructor. +makeExample('cb-dependency-injection/ts/app/sorted-heroes.component.ts','sorted-heroes','app/sorted-heroes.component.ts (SortedHeroesComponent)') :marked @@ -653,78 +1140,146 @@ figure.image-display But Angular calls the *derived* class's `ngOnInit` *before* calling the base class's `ngOnInit` so we'd be sorting the heroes array *before they arrived*. That produces a nasty error. + Ahora hay que tomar nota sobre el método `afterGetHeroes`. + La primera solución fue crear un método `ngOnInit` en la clase `SortedHeroesComponent` y hacer el ordenamiento ahí.. + Pero Angular llama *primero* a la clase *derivada* antes de llamar al método `ngOnInit` de la clase base + entonces se está ordenando el arreglo de héroes *antes de recibirlos*. Esto produce un error. + Overriding the base class's `afterGetHeroes` method solves the problem + Sustituir el método `afterGetHeroes` de la clase base resuelve el problema + These complications argue for *avoiding component inheritance*. + + Estas complicaciones hablan a favor de *evitar la herencia de componentes*. a(id="find-parent") .l-main-section :marked ## Find a parent component by injection + ## Encontrar un componente padre mediante la inyección + Application components often need to share information. We prefer the more loosely coupled techniques such as data binding and service sharing. But sometimes it makes sense for one component to have a direct reference to another component perhaps to access values or call methods on that component. + + A menudo los componentes de la aplicación necesitan compartir información. + Para ello, son preferibles las técnicas débilmente acopladas, como el enlace de datos y el intercambio de servicios. + Pero a veces tiene más sentido para un componente tener una referencia directa a otro componente + quizá para tener acceso a ciertos valores o llamar algunos métodos de ese componente. Obtaining a component reference is a bit tricky in Angular. Although an Angular application is a tree of components, there is no public API for inspecting and traversing that tree. + Obtener una referencia a un componente en Angular es un poco más complicado. + A pesar de que una aplicación de Angular tiene un árbol de componentes, + no hay un API que pueda inspeccionar y recorrer ese árbol. + + There is an API for acquiring a child reference (checkout `Query`, `QueryList`, `ViewChildren`, and `ContentChildren`). + Hay un API para obtener la referencia a un hijo + (puede revisar `Query`, `QueryList`, `ViewChildren`, y `ContentChildren`). + There is no public API for acquiring a parent reference. But because every component instance is added to an injector's container, we can use Angular dependency injection to reach a parent component. + No hay un API pública para obtener una referencia al padre. + Pero gracias a que cada instancia de un componente es añadida en el contenedor del inyector, + puede usarse la inyección de dependencias de Angular para llegar al componente padre. + This section describes some techniques for doing that. + En esta sección de describen algunas técnicas para lograr ésto. + ### Find a parent component of known type + ### Encontrar un componente padre de un tipo dado + We use standard class injection to acquire a parent component whose type we know. + Se usa una inyección de clase estándar para obtener el componente padre cuyo tipo se conoce previamente. + In the following example, the parent `AlexComponent` has several children including a `CathyComponent`: + + En el siguiente ejemplo, el componente padre `AlexComponent` tiene varios hijos incluyendo a `CathyComponent`: a(id='alex') +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','alex-1','parent-finder.component.ts (AlexComponent v.1)')(format='.') :marked *Cathy* reports whether or not she has access to *Alex* after injecting an `AlexComponent` into her constructor: + + *Catchy* informa si tiene o no acceso a *Alex* + despues de inyectar al componente `AlexComponent` en su constructor: +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','cathy','parent-finder.component.ts (CathyComponent)')(format='.') :marked We added the [@Optional](#optional) qualifier for safety but the confirms that the `alex` parameter is set. + + Se añadió el decorador de calificación[@Optional](#optional) por seguridad pero + el ejemplo + confirma que el parámetro `alex` se ha establecido. ### Cannot find a parent by its base class + ### No se puede encontrar un padre mediante su clase base. + What if we do *not* know the concrete parent component class? + ¿Qué pasa si no se conoce la clase base del padre? + A re-usable component might be a child of multiple components. Imagine a component for rendering breaking news about a financial instrument. For sound (cough) business reasons, this news component makes frequent calls directly into its parent instrument as changing market data stream by. + Un componente re-usable puede ser hijo de varios componentes. + Imagínese un componente para la representación de noticias de última hora sobre un instrumento financiero. + Por razónes de negocios, éste componente de noticias hace frecuentes llamados + directamente dentro de su instrumento padre como el cambio de flujo de datos de mercado. + The app probably defines more than a dozen financial instrument components. If we're lucky, they all implement the same base class whose API our `NewsComponent` understands. + La aplicación probablemente define más de una docena de componentes de instrumentos financieros. + Si se tiene suerte, todos esos componentes implementan la misma clase base + la cual entiende la API `NewsComponent`. + .l-sub-section :marked Looking for components that implement an interface would be better. That's not possible because TypeScript interfaces disappear from the transpiled JavaScript which doesn't support interfaces. There's no artifact we could look for. + + Buscar componentes que implementan una interfaz es mejor. + Pero eso no es posible ya que las interfaces de TypeScript desaparecen al cambiar el código a JavaScript + el cual no tienen soporte para interfaces. No hay éxiste algo que buscar. + :marked We're not claiming this is good design. We are asking *can a component inject its parent via the parent's base class*? + Pero no se afirma que este no sea un buen diseño + Se plantea la pregunta *¿Puede un componente inyectar su componenete padre mediante la clase base*? + The sample's `CraigComponent` explores this question. [Looking back](#alex) we see that the `Alex` component *extends* (*inherits*) from a class named `Base`. + + El ejemplo `CraigComponent` explora está pregunta [Mirar hacia atrás](#alex) + se puede observar que el componente `Alex` *extiende* (*hereda*) de la clase `Base`. +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','alex-class-signature','parent-finder.component.ts (Alex class signature)')(format='.') :marked The `CraigComponent` tries to inject `Base` into its `alex` constructor parameter and reports if it succeeded. + El componente `CraigComponent` intenta inyectar la clase`Base` dentro del parámetro `alex` del constructor e informa si tuvo éxito. +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','craig','parent-finder.component.ts (CraigComponent)')(format='.') :marked Unfortunately, this does not work. @@ -732,29 +1287,53 @@ a(id='alex') confirms that the `alex` parameter is null. *We cannot inject a parent by its base class.* + Desafortunadamente esto no funciona. + El ejemplo + confirma que el valor del parámetro `alex` es nulo. + *No puede inyectarse un padre mediante su clase base* + ### Find a parent by its class-interface + ### Encontrar un padre mediante su clase-interfaz + We can find a parent component with a [class-interface](#class-interface). + + Puede hallarse un componente padre con su [clase-interfaz](#class-interface). The parent must cooperate by providing an *alias* to itself in the name of a *class-interface* token. + + El padre debe proveer un *alias* para si mismo en el nombre del token de la *clase-interfaz*. Recall that Angular always adds a component instance to its own injector; that's why we could inject *Alex* into *Carol* [earlier](#known-parent). + + Recuerde que Angular siempre agrega una instancia del componente a su propio inyector; + es por eso que se puede inyectar el componente *Alex* dentro del componente *Carol* [anteriormente](#known-parent). We write an [*alias provider*](#useexisting) — a `provide` object literal with a `useExisting` definition — that creates an *alternative* way to inject the same component instance and add that provider to the `providers` array of the `@Component` metadata for the `AlexComponent`: + + Se escribe un [*proveedor alias*]#useexisting) — un objeto `provide` con una definición `useExisting` — + y se agrega al proveedor en el arreglo `providers` de los metadatos del `@Component` en la clase `AlexComponent`: a(id="alex-providers") +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','alex-providers','parent-finder.component.ts (AlexComponent providers)')(format='.') :marked [Parent](#parent-token) is the provider's *class-interface* token. The [*forwardRef*](#forwardref) breaks the circular reference we just created by having the `AlexComponent` refer to itself. + + [Padre](#parent-token) es el proveedor del token de la *clase-interfaz*. + El [*forwardRef*](#forwardref) rompe la referencia circular que se acaba de crear haciendo que el componente `Alex Component` se refiera a sí mismo. *Carol*, the third of *Alex*'s child components, injects the parent into its `parent` parameter, the same way we've done it before: + + *Carol*, el tercer hijo del componente *Alex*, inyecta al padre dentro de su parámetro `parent`, de la misma forma que se hizó anteriormente: +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','carol-class','parent-finder.component.ts (CarolComponent class)')(format='.') :marked Here's *Alex* and family in action: + + A continuación se muestra al componente *Alex* y a su familia en acción: figure.image-display img(src="/resources/images/cookbooks/dependency-injection/alex.png" alt="Alex in action") @@ -762,20 +1341,36 @@ a(id="parent-tree") :marked ### Find the parent in a tree of parents + ### Encontrar el componente padre en un árbol de componentes padre. + Imagine one branch of a component hierarchy: *Alice* -> *Barry* -> *Carol*. Both *Alice* and *Barry* implement the `Parent` *class-interface*. + Imaginese un nivel de la jerarquía del componente: *Alice* -> *Barry* -> *Carol*. + *Alice* y *Barry* implementan la *clase-interfaz* `Parent`. + *Barry* is the problem. He needs to reach his parent, *Alice*, and also be a parent to *Carol*. That means he must both *inject* the `Parent` *class-interface* to get *Alice* and - *provide* a `Parent` to satisfy *Carol*. + *provide* a `Parent` to satisfy *Carol*. + + El componente *Barry* es en problema. Éste necesita llegar a su componente padre, *Alice* y a su vez ser padre de *Carol*. + Lo que significa que ambos deben *inyectar* la *clase-interfaz* `Parent` para acceder al componente *Alice* y + *proveer* un `Parent` para *Carol*. Here's *Barry*: + + Este es el componente *Barry*; +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','barry','parent-finder.component.ts (BarryComponent)')(format='.') :marked *Barry*'s `providers` array looks just like [*Alex*'s](#alex-providers). If we're going to keep writing [*alias providers*](#useexisting) like this we should create a [helper function](#provideparent). + El arreglo `providers` de *Barry* es igual al de [*Alex's*](#alex-providers). + Si se seguirán escribiendo asi los [*proveedores de alias*](#useexisting) debe crearce una [función auxiliar](#provideparent). + For now, focus on *Barry*'s constructor: + + Por ahora, hay que poner atención en el constructor del componente *Barry* +makeTabs( 'cb-dependency-injection/ts/app/parent-finder.component.ts, cb-dependency-injection/ts/app/parent-finder.component.ts', 'barry-ctor, carol-ctor', @@ -784,16 +1379,28 @@ a(id="parent-tree") :marked It's identical to *Carol*'s constructor except for the additional `@SkipSelf` decorator. + Es igual al constructor de *Carol* excepto por el decorador adicional `@SkipSelf`. + `@SkipSelf` is essential for two reasons: + + El decorador `@SkipSelf` es fundamental por dos razonez; 1. It tell the injector to start its search for a `Parent` dependency in a component *above* itself, which *is* what parent means. + 1. Este le indica al inyector que inicie su búsqueda en la dependencia `Parent`, que está un componente *encima* de él. + 2. Angular throws a cyclic dependency error if we omit the `@SkipSelf` decorator. + 2. Angular lanza un error de dependencia cíclica si se decide omitir el decorador `@SkipSelf`. + `Cannot instantiate cyclic dependency! (BethComponent -> Parent -> BethComponent)` + + `¡No puede instanciarse una dependencia cíclica! (BethComponent -> Parent -> BethComponent)` Here's *Alice*, *Barry* and family in action: + + A continuación se observa a los componentes *Alice*, *Barry* y su familia en acción: figure.image-display img(src="/resources/images/cookbooks/dependency-injection/alice.png" alt="Alice in action") @@ -802,47 +1409,82 @@ a(id="parent-token") :marked ### The *Parent* class-interface We [learned earlier](#class-interface) that a *class-interface* is an abstract class used as an interface rather than as a base class. + + ### La clase-interfaz *Padre* + [Se aprendió anteriormente](#class-interface) que una *clase-interfaz* es una clase abstracta usada como interfaz en lugar de como una clase base. Our example defines a `Parent` *class-interface* . + + El ejemplo define una *clase- interfaz* `Parent`. +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','parent','parent-finder.component.ts (Parent class-interface)')(format='.') :marked The `Parent` *class-interface* defines a `name` property with a type declaration but *no implementation*., The `name` property is the only member of a parent component that a child component can call. Such a narrowing interface helps decouple the child component class from its parent components. + La *clase-interfaz* `Parent` define una propiedad llamada `name` con un tipo, pero sin *implementación*., + La propiedad `name` es el único miembro del componente padre que un hijo puede llamar. + + A component that could serve as a parent *should* implement the *class-interface* as the `AliceComponent` does: + + Un componente puede actuar como padre *siempre que* implemente la *clase-interfaz* como lo hace el componente `AliceComponent`: +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','alice-class-signature','parent-finder.component.ts (AliceComponent class signature)')(format='.') :marked Doing so adds clarity to the code. But it's not technically necessary. Although the `AlexComponent` has a `name` property (as required by its `Base` class) its class signature doesn't mention `Parent`: + + Haciendo eso, el código queda más claro. Pero no es tecnicamente necesario. + A pesar de que el componente `AlexComponent` tiene una propiedad name` (requerido por la clase `Base`) + su clase no menciona un componente `Parent`: + +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','alex-class-signature','parent-finder.component.ts (AlexComponent class signature)')(format='.') .l-sub-section :marked The `AlexComponent` *should* implement `Parent` as a matter of proper style. It doesn't in this example *only* to demonstrate that the code will compile and run without the interface + El componente `AlexComponent` *debe* implentar la clase `Parent` por suestion de estilo propio. + No se hace en éste ejemplo *sólo* para demostrar que el código compila y se ejecuta sin problemas aun sin la interfaz. + + a(id="provideparent") :marked ### A *provideParent* helper function + ### La función auxiliar *provideParent* + Writing variations of the same parent *alias provider* gets old quickly, especially this awful mouthful with a [*forwardRef*](#forwardref): + + Escribir variantes del mismo *proveedor de alias* padre se vuelve obsoleto rápidamente, + especialmente ésta [*forwardRef*](#forwardref): +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','alex-providers')(format='.') :marked We can extract that logic into a helper function like this: + + Puede extraerse ésta lógica hacia una función auxiliar como a continuación se observa: +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','provide-the-parent')(format='.') :marked Now we can add a simpler, more meaningful parent provider to our components: + + Ahora puede añadirse un proveedor de padres más sencillo a los componentes: +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','alice-providers')(format='.') :marked We can do better. The current version of the helper function can only alias the `Parent` *class-interface*. Our application might have a variety of parent types, each with its own *class-interface* token. + Ésto puede mejorarse. La versión actual de la función auxiliar sólo puede dar un alias a la *clase-interfaz* `Parent`. + La aplicación puede tener varios tipos de padres, cada unno con su propio token de *clase-interfaz* + Here's a revised version that defaults to `parent` but also accepts an optional second parameter for a different parent *class-interface*. + A continuación se observa otra versión que es `parent`por defecto pero también acepta un segundo parámetro opcional para un tipo diferente de *clase-interfaz* padre. +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','provide-parent')(format='.') :marked And here's how we could use it with a different parent type: + + Y así es como podría utilizarse con un tipo diferente de padres: +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','beth-providers')(format='.') :marked @@ -851,24 +1493,46 @@ a(id="forwardref") :marked ## Break circularities with a forward class reference (*forwardRef*) + ## Romper la circularidad con una referencia de clase hacia adelante (*forwardRef*) + The order of class declaration matters in TypeScript. We can't refer directly to a class until it's been defined. + En TypeScript el orden de la declaración de clases es muy importante. + No puede referirse a una clase que aun no ha sido declarada. + This isn't usually a problem, especially if we adhere to the recommended *one class per file* rule. But sometimes circular references are unavoidable. We're in a bind when class 'A refers to class 'B' and 'B' refers to 'A'. One of them has to be defined first. + Ésto no es un problema, en especial si se ha seguido la recomendación de *una clase por archivo*. + Pero a veces las referencias circulares son inevitables. + Exíste un conflicto cuando una clase 'A hace referecia a una clase 'B' y la clase 'B' hace una referencia a la clase 'A'. + Una de ellas tuvo que haber sido declarada primero. + The Angular `forwardRef` function creates an *indirect* reference that Angular can resolve later. + La función `forwardRef` de Angular crea *indirectamente* una referencia que puede resolver despues. + The *Parent Finder* sample is full of circular class references that are impossible to break. + El ejemplo *Parent Finder* está lleno de referencias de clase circulares que son imposibles de romper. + :marked We face this dilemma when a class makes *a reference to itself* as does the `AlexComponent` in its `providers` array. The `providers` array is a property of the `@Component` decorator function which must appear *above* the class definition. + Se enfrentará a este dilema cuando una clase hace *una referencia a si misma* + como lo hace el componente `AlexComponent` en su arreglo `providers`. + El arreglo `providers` es una propiedad del decorador de función `@Component` el cual + debe estar *encima* de la definición de la clase. + + We break the circularity with `forwardRef`: + + Se rompe la circularidad con la función `forwardRef`: +makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','alex-providers','parent-finder.component.ts (AlexComponent providers)')(format='.') :marked