Injeção de dependência em Angular: um guia abrangente

Inyección de dependencia en Angular: una guía completa

Aprenda a dominar la inyección de dependencias en Angular con nuestro tutorial fácil de seguir. Descubra los beneficios de esta poderosa técnica y lleve el desarrollo de su aplicación al siguiente nivel.

Imagem em destaque

Angular es un marco de código abierto para crear aplicaciones web modernas. Uno de los principios clave de Angular es la inyección de dependencia. Es un patrón de diseño que permite la creación de aplicaciones eficientes y escalables.

En esta guía completa, exploraremos qué es la inyección de dependencia en el flujo de trabajo de una empresa de desarrollo Angular, los beneficios, la implementación y las mejores prácticas. Ya sea que sea nuevo en una empresa de desarrollo de Angular o un desarrollador experimentado, esta guía lo ayudará a dominar el arte de crear aplicaciones eficientes y escalables utilizando la inyección de dependencia de Angular.

¡Profundicemos en el mundo de la inyección de dependencia!

Descripción general de la inyección de dependencia angular

¿Qué es la inyección de dependencia?

La inyección de dependencia (DI) es un patrón de diseño. La inyección de dependencia angular es un mecanismo donde se crean inyecciones de dependencia de componentes o servicios. Luego se inyecta en tiempo de ejecución en lugar de crearse dentro del servicio o componente. Esto permite la creación de código modular y débilmente acoplado. Esto significa que los componentes y servicios sólo deben preocuparse por cuáles son las dependencias, en lugar de crearlas.

Hay tres tipos de métodos de inyección de dependencia en Angular que se pueden utilizar para proporcionar dependencias a componentes y servicios. Son los siguientes.

Tipo de inyección Descripción
Inyección de constructores Proporciona dependencias utilizando la función constructora de clases.
Inyección de colocador Se utiliza un método de establecimiento para inyectar la dependencia a través del inyector.
Inyección de interfaz La dependencia proporciona un método de inyector que inyecta dependencia en cualquier cliente que se le pase. El cliente también necesita tener un método de establecimiento listo para aceptar la inyección de dependencia angular.

El uso de los métodos anteriores varía según el escenario y también depende de los requisitos de la aplicación. Veamos los beneficios de la inyección de dependencia en Angular.

Los beneficios de utilizar la inyección de dependencia en Angular

La inyección de dependencia ofrece muchos beneficios críticos e importantes para las aplicaciones Angular. Veamos algunos de ellos.

  1. El componente y la clase de servicio son más modulares.
  2. La configuración compleja y la maqueta son innecesarias; Podemos realizar pruebas de forma aislada, ya que es mucho más fácil.
  3. Debido a la modularidad del código, se puede reutilizar muy fácilmente.
  4. Codebase ahora es más fácil de administrar.

Comprender la inversión de control (IoC) y su papel en DI

En Inversión de Control (IoC), el componente o servicio no es responsable de gestionar sus dependencias. Por lo tanto, debe inyectarse en un recipiente o estructura separada. Es un principio de diseño estrechamente vinculado a la inyección de dependencia. La responsabilidad debería revertirse. Esto significa que debe inyectarse en un recipiente o marco separado.

En el siguiente código se puede ver un ejemplo de IoC y DI en Angular.

 importar {Componente} desde '@angular/core';
 importar {ProductService} desde './product.service';

 @Componente({
 selector: 'lista-de-productos-aplicaciones',
 URL de plantilla: './lista-de-productos.component.html',
 })
 clase de exportación ProductListComponent {
 productos: cualquiera;

 constructor (servicio de producto privado: servicio de producto) {}

 ngOnInit {
  this.products = this.productService.getProducts;
 }
 }

En este ejemplo, ProductListComponent depende de la clase de exportación ProductServiceProductService. En lugar de crear una instancia de ProductService dentro de ProductListComponent. La función constructora se utiliza para inyectar ProductService en el componente a través del constructor.

El propio ProductService puede tener dependencias de otros servicios, pero no necesita preocuparse por crear estas dependencias porque el marco DI es responsable de crear las instancias de estos servicios e inyectarlas en ProductService.

Conceptos básicos en inyección de dependencia angular

La inyección de dependencia se ve facilitada por varios conceptos básicos. Es importante comprender estos conceptos para utilizar eficazmente la inyección de dependencia angular.

Proveedores

Los proveedores son objetos responsables de crear y administrar instancias de dependencias que se pueden inyectar en componentes y servicios. Se puede definir a nivel de componente, módulo o aplicación. Debe utilizar la propiedad Proveedor para implementarlo en Angular. Veamos un ejemplo para ver cómo se implementa.

 importar {Componente, Inyectable} desde '@angular/core';

 @Inyectable
 exportar clase MiServicio {
 obtener datos {
  devolver "Datos de MyService";
 }
 }

 @Componente({
 selector: 'mi-componente',
 proveedores: (MiServicio),
 plantilla: ' {{ data }} '
 })
 clase de exportación MiComponente {
 constructor(miServicio privado: MiServicio) {}

 datos = this.myService.getData;
 }

El ejemplo anterior define una clase MyService con un decorador @Injectable. Angular debe inyectar la clase MyService como una dependencia.

propiedad useClass

También es importante especificar qué clases se utilizarán como dependencias. Veamos la propiedad useClass.

importar {Componente, Inyectable} desde '@angular/core';

 @Inyectable
 exportar clase MiServicio {
 obtener datos {
  devolver "Datos de MyService";
 }
 }

 @Inyectable
 exportar clase MiOtroServicio {
 obtener datos {
  devolver "Datos de MyOtherService";
 }
 }

 @Componente({
 selector: 'mi-componente',
 proveedores: ({ proporcionar: MiServicio, useClass: MiOtroServicio }),
 plantilla: ' {{ data }} '
 })
 clase de exportación MiComponente {
 constructor(miServicio privado: MiServicio) {}

 datos = this.myService.getData;
 }

propiedad useValue

Esta propiedad se utiliza para especificar un valor que debe usarse como dependencia. Una implementación de ejemplo es la siguiente:

 importar {Componente} desde '@angular/core';

 const myValue = "Datos de useValue";

 @Componente({
 selector: 'mi-componente',
 proveedores: ({ proporcionar: 'MiValor', usarValor: miValor }),
 plantilla: ' {{ data }} '
 })
 clase de exportación MiComponente {
 constructor(@Inject('MyValue') datos privados: cadena) {}
 }

En el ejemplo anterior, la propiedad useValue Providers especifica y proporciona un valor de cadena. El valor se inyecta en la propiedad de datos utilizando el decorador @Inject.

propiedad useFactory

Esta propiedad se usa para especificar una función de fábrica que debe usarse para crear una dependencia. Veamos un ejemplo.

 importar {Componente} desde '@angular/core';

 función de exportación myFactory {
 devolver "Datos de useFactory";
 }

 @Componente({
 selector: 'mi-componente',
 proveedores: ({ proporcionar: 'MyValue', useFactory: myFactory }),
 plantilla: ' {{ data }} '
 })
 clase de exportación MiComponente {
 constructor(@Inject('MyValue') datos privados: cadena) {}
 }

El atributo useFactory se utiliza para definir y proporcionar una función de fábrica en el ejemplo anterior. El decorador @Inject indica a la aplicación que establezca la propiedad de datos en el valor devuelto por la función de fábrica.

utilizarPropiedad existente

Esta propiedad se utiliza para especificar una dependencia existente que debe usarse como valor de la nueva dependencia. Veamos un ejemplo.

 importar {Componente, Inyectable} desde '@angular/core';

 @Inyectable
 exportar clase MiServicio {
 obtener datos {
  devolver "Datos de MyService";
 }
 }

 @Inyectable
 exportar clase MiOtroServicio {
 obtener datos {
  devolver "Datos de MyOtherService";
 }
 }

 @Componente({
 selector: 'mi-componente',
 proveedores: (MiServicio, {proporcionar: MiOtroServicio, usarExistente: MiServicio}),
 plantilla: ' {{ data }} '
 })
 clase de exportación MiComponente {
 constructor(privado miOtroServicio: MiOtroServicio) {}

 datos = this.myOtherService.getData;
 }

El decorador @Injectable se utiliza para definir MyService y MyOtherService en el ejemplo anterior. Usando la propiedad useExisting, la clase MyComponent declara que MyService debe usarse como valor de MyOtherService.

Inyectores

El inyector es responsable de crear y gestionar dependencias. Una aplicación completa tiene un inyector raíz que Angular crea automáticamente. Todos los demás inyectores creados posteriormente son hijos del inyector raíz. Veamos un ejemplo.

 importar {Componente, Inyectable, Inyector} desde '@angular/core';

 @Inyectable
 exportar clase MiServicio {
 obtener datos {
  devolver "Datos de MyService";
 }
 }

 @Componente({
 selector: 'mi-componente',
 plantilla: ' {{ data }} '
 })
 clase de exportación MiComponente {
 constructor(inyector privado: Inyector) {}

 datos = this.injector.get(MyService).getData;
 }

En el código anterior, la clase MyService se define con un decorador @Injectable. Esto significa que la clase se puede inyectar como una dependencia. La clase MyComponent define una dependencia de Injector utilizando el constructor para inyectar una instancia de Injector. Luego, la propiedad de datos se establece en el resultado de llamar al método getData en una instancia de MyService que se recupera utilizando el método get en la instancia del inyector.

Archivos

El token de inyección de dependencia en Angular se utiliza para identificar una dependencia representada por una cadena o clase. Es importante tener en cuenta que el token de inyección se utiliza con la propiedad proporcionada para especificar qué dependencia se debe utilizar para el token proporcionado. Veamos el ejemplo de implementación de la siguiente manera:

 importar {Componente, Inyectable, Inyectar} desde '@angular/core';

 exportar const MY_TOKEN = 'myToken';

 @Inyectable
 exportar clase MiServicio {
 obtener datos {
  devolver "Datos de MyService";
 }
 }

 @Componente({ 
selector: 'mi-componente',
 proveedores: ({ proporcionar: MY_TOKEN, useClass: MyService }),
 plantilla: ' {{ data }} '
 })
 clase de exportación MiComponente {
 constructor(@Inject(MY_TOKEN) myService privado: MyService) {}

 datos = this.myService.getData;
 }

En el ejemplo de código anterior, la clase MyService le dice a Angular que esta clase se puede inyectar como una dependencia. La clase MyComponent define una dependencia de MyService especificándola como el valor de la propiedad proporcionada mediante el token MY_TOKEN. El decorador @Inject se utiliza para inyectar una instancia de MyService en la propiedad myService de la clase MyComponent. Luego, la propiedad de datos se establece en el resultado de llamar al método getData en myService.

Implementación de inyección de dependencia en Angular

Esta sección del artículo se centrará en la implementación de la inyección de dependencia angular.

Requisitos previos

Debes tener lo siguiente:

  • Node.js: la última versión de Node.js en su máquina.
  • Un editor de código: cualquier IDE que admita Angular.
  • npm: Administrador de paquetes de nodo para instalar las dependencias necesarias.
  • Angular CLI: la última versión que proporciona Angular core.

Instalar las dependencias necesarias

Si no tiene Angular preinstalado en su máquina. Utilice el siguiente comando en la terminal para instalar Angular CLI:

 instalación npm -g @angular/cli

Crear un nuevo proyecto

Para crear un nuevo proyecto Angular y una aplicación de inicio, ejecute el comando CLI ng new y proporcione el nombre my-app.

 ng nueva mi aplicación

Su archivo package.json debería verse así:

Tenga en cuenta que las versiones de dependencia se especifican en el archivo anterior. Estas eran las versiones al momento de crear esta guía.

Implementación

A continuación, es necesario crear un servicio para que se pueda configurar la inyección para los componentes. Los servicios son clases que proporcionan funcionalidad para toda la aplicación. Puede crear un servicio utilizando Angular CLI ejecutando el siguiente comando.

 ng generar servicio mi-servicio

Una vez creado el servicio, deberá registrarlo en el sistema de inyección de dependencia de Angular. Puede hacer esto agregándolo a la matriz de proveedores en el módulo de la aplicación. El componente raíz se agrega aquí de forma predeterminada. Abra el archivo app.module.ts y agregue la siguiente línea.

 importar { MyServiceService } desde './my-service.service';

 @NgModule({
 declaraciones: (
  Componente de aplicación
 ),
 importaciones: (
  módulo de navegador,
  Módulo de enrutamiento de aplicaciones
 ),
 proveedores: (MyServiceService), // agrega el servicio aquí
 arranque: (Componente de aplicación)
 })
 exportar clase AppModule { }

Inyectar dependencias en componentes y servicios

Ahora que el servicio está configurado y registrado con el sistema de inyección de dependencia. Se puede inyectar en el componente principal o en los componentes secundarios. Para hacer esto, debe agregar un constructor al componente y especificar el servicio como parámetro. Por ejemplo, piense en un componente MyComponent que necesita utilizar el servicio MyService. Puede inyectar el servicio en el componente de esta manera. Deberías agregar esto en el archivo ts de mi componente.

 importar {Componente} desde '@angular/core';
 importar { MyServiceService } desde '../my-service.service';

 @Componente({
 selector: 'mi-componente',
 plantilla: '<p> {{ getMessage }} </p>'
 })
 clase de exportación MiComponente {

 constructor(myService privado: MyServiceService) {}

 obtener mensaje: cadena {
  devolver this.myService.getMessage;
 }
 }

En el constructor del componente, MyServiceService se especifica como parámetro. También se define un método getMessage que recupera datos del servicio.

A continuación, en lugar de registrar un servicio con un módulo, podemos usar provideIn para registrar el servicio con el inyector raíz. Podemos hacer esto especificando provideIn: 'root' en el decorador @Injectable de nuestro servicio.

 importar {Inyectable} desde '@angular/core';

 @Inyectable({
 proporcionado en: 'raíz'
 })
 clase de exportación MyServiceService {
 obtener mensaje: cadena {
  return '¡Hola desde MyService!';
 }
 }

Esto registrará el servicio con el inyector raíz. Esto lo hace disponible para cualquier componente de nuestra aplicación. También puede obtener datos de servicios de fuentes externas. Así es como registras servicios en Angular.

Inyección de dependencia en directivas y canalizaciones

Para inyectar servicios y otras dependencias en directivas y canales, debe agregar un constructor y especificar las dependencias como parámetros.

Por ejemplo, digamos que tiene una directiva personalizada que necesita utilizar el servicio MyService. Puede inyectar el servicio en la directiva de esta manera.

Primero, cree un nuevo archivo de directiva custom.directive.ts en la carpeta de la aplicación. Agregue el siguiente código.

 importar {Directiva, Entrada, ElementRef} desde '@angular/core';

 @Directiva({
 selector: '(directiva personalizada)'
 })
 clase de exportación CustomDirective {
 @Input customDirective: cadena;

 constructor (el privado: ElementRef) {
  this.customDirective="";
 }

 ngOnInit {
  this.el.nativeElement.style.color = this.customDirective;
 }
 }

Esta directiva toma una entrada de tipo cadena y la usa para cambiar el color del elemento al que se aplica.

A continuación, en el archivo app.module.ts, importe CustomDirective y agréguelo a las declaraciones y matrices de exportación. Este archivo es el módulo raíz de la aplicación. En las declaraciones puedes ver todos los componentes y la directiva.

 importar {NgModule} desde '@angular/core';
 importar {BrowserModule} desde '@angular/platform-browser';

 importar { AppComponent } desde './app.component';
 importar { MyServiceService } desde './my-service.service'; 
importar {MiComponente} desde './mi-componente/mi-componente.componente';
 importar { CustomDirective } desde './custom.directive';

 @NgModule({
 declaraciones: (
 componente de aplicación,
 mi componente,
 CustomDirective // ​​​​agregar aquí
 ),
 importaciones: (
 módulo de navegador,
 ),
 proveedores: (MiServicioServicio),
 arranque: (Componente de aplicación)
 })
 exportar clase AppModule { }

Finalmente, en el archivo app.component.html, aplique la directiva a un elemento y pase el color deseado. Agregue mi componente también.

 <h1 customDirective="red">¡Hola mundo!</h1>
 <mi-componente></mi-componente>

Ejecute la aplicación

Abra una ventana de terminal y navegue hasta el directorio raíz de su proyecto. Ejecute el comando ngserve para iniciar el servidor de desarrollo.

Abra un navegador web y navegue para ver la aplicación.

Así debería verse la página web.

Inyección de dependencia jerárquica

La inyección de dependencia crea una estructura de inyectores en forma de árbol. Cada inyector de componente puede acceder al servicio proporcionado por los inyectores principal y raíz. Siempre que una clase de componente solicita un servicio, Angular lo busca en el inyector actual. Si no lo encuentra, buscará en el árbol de inyectores hasta encontrar un proveedor.

Pruebas con inyección de dependencia

TestBed es una utilidad proporcionada por Angular para realizar pruebas. Le permite configurar y crear un módulo de prueba. Puede utilizar el método TestBed.configureTestingModule para configurar el módulo de prueba con las dependencias y proveedores necesarios.

Veamos cómo se hacen las pruebas.

Probando un componente con un servicio inyectado.

 importar {ComponentFixture, TestBed} desde '@angular/core/testing';
 importar {MiComponente} desde './mi.componente';
 importar {MiServicio} desde './mi.servicio';

 describir('MiComponente', => {
 dejar componente: MiComponente; 
dejar accesorio: ComponentFixture<MiComponente>;

 antes de cada uno (async => {
 espere TestBed.configureTestingModule({
 declaraciones: (MiComponente),
 proveedores: (MiServicio)
 })
 .compileComponentes;
 });

 antes de cada uno( => {
 accesorio = TestBed.createComponent(MiComponente);
 componente = accesorio.componentInstance;
 accesorio.detectChanges;
 });

 it('debería crear', => {
 esperar(componente).toBeTruthy;
 });

 it('debería usar servicio inyectado', => {
 servicio constante = TestBed.inject(MyService);
 spyOn(servicio, 'getData').and.returnValue('datos de prueba');
 expect(component.getDataFromService).toEqual('datos de prueba');
 });
 });

Probando un servicio con dependencias inyectadas.

 importar { TestBed } desde '@angular/core/testing';
 importar {MiServicio} desde './mi.servicio';
 importar {HttpClient} desde '@angular/common/http';
 importar {de} desde 'rxjs';

 describir('MiServicio', => {
 dejar servicio: MyService;
 dejar httpSpy: jasmine.SpyObj<HttpClient>;
 
antes de cada uno( => {
 httpSpy = jasmine.createSpyObj('HttpClient', ('obtener'));
 TestBed.configureTestingModule({
 proveedores: (
 mi servicio,
 { proporcionar: HttpClient, useValue: httpSpy }
 )
 });
 servicio = TestBed.inject(MiServicio);
 });

 it('debería crearse', => {
 esperar(servicio).toBeTruthy;
 });

 it('debería devolver los datos esperados', => {
 const datos esperados = { mensaje: 'mensaje de prueba' };
 httpSpy.get.and.returnValue(de(datos esperados));
 servicio.getData .subscribe((datos) => {
 esperar(datos).toEqual(datos esperados);
 });
 });
 });

En algunos casos, es posible que desee probar un componente o servicio de forma aislada de sus dependencias. Para ello, puedes utilizar espías o servicios simulados. Una función espía registra todas las llamadas que se le realizan y luego se utiliza para validarlas en las pruebas. Un servicio simulado es una implementación de servicio falsa que le permite controlar su comportamiento y devolver valores.

Mejores prácticas y errores comunes

Es importante abordar algunas de las mejores prácticas y errores comunes al trabajar en Angular.

  • Es esencial distinguir entre servicios y sus proveedores. Esto tiene el potencial de simplificar las pruebas y el mantenimiento del código.
  • Cada servicio solo debe crearse una vez y compartirse en toda la aplicación, lo que puede reducir significativamente la sobrecarga y aumentar la velocidad.
  • Las dependencias circulares son un error típico que se debe evitar al utilizar la inyección de dependencia. Esto puede suceder si dos o más servicios dependen entre sí de alguna manera. Como resultado, se crea un círculo vicioso de dependencia, que puede ser difícil de controlar y dar lugar a errores. Para evitar esto, es crucial examinar las interdependencias entre los servicios y organizarlas para que no haya bucles.

Si te gustó este artículo, mira:

  • Dominar el enrutamiento angular: una guía completa
  • Estructura de proyecto angular: mejores prácticas para archivos y carpetas
  • Dominar el enlace de datos angular: una guía completa para expertos
  • Principales bibliotecas y marcos de componentes de Angular UI
  • ¿Qué es Angular y por qué su empresa debería considerarlo para su desarrollo?
  • Los mejores frameworks Javascript de la actualidad
  • Angular para empresas
  • ¿Cuál es el mejor framework para el desarrollo web?

Conclusión

Comprender e implementar la inyección de dependencia en Angular es fundamental para crear aplicaciones escalables y mantenibles, ya sea que esté directamente involucrado o subcontrate el desarrollo de software de Angular. A través de esta guía, cubrimos los conceptos básicos de la inyección de dependencia angular y una implementación de ejemplo para aclarar la comprensión.

Si sigue la guía paso a paso y el ejemplo, debería comprender cómo utilizar la inyección de dependencia en sus propios proyectos de Angular o al subcontratar el desarrollo de software de Angular. Con este conocimiento, los desarrolladores pueden crear aplicaciones que sean más eficientes, flexibles y fáciles de mantener.

Fuente: BairesDev

Conteúdo Relacionado

O Rails 8 sempre foi um divisor de águas...
A GenAI está transformando a força de trabalho com...
Entenda o papel fundamental dos testes unitários na validação...
Aprenda como os testes de carga garantem que seu...
Aprofunde-se nas funções complementares dos testes positivos e negativos...
Vídeos deep fake ao vivo cada vez mais sofisticados...
Entenda a metodologia por trás dos testes de estresse...
Descubra a imprevisibilidade dos testes ad hoc e seu...
A nomeação de Nacho De Marco para o Fast...
Aprenda como os processos baseados em IA aprimoram o...
A web está em constante evolução, e com ela,...
A Inteligência Artificial (IA) tem sido um tema cada...
Você já se sentiu frustrado com a complexidade de...
O OpenStack é uma plataforma de computação em nuvem...
Você já se sentiu frustrado com a criação de...
A era digital trouxe uma transformação profunda na forma...
Nos dias atuais, a presença digital é fundamental para...
Introdução Quando se trata de desenvolvimento de software, a...
Como desenvolvedor Dart, você provavelmente já se deparou com...
Regresar al blog

Deja un comentario

Ten en cuenta que los comentarios deben aprobarse antes de que se publiquen.