Cómo manejar objetos globales en Angular: buenas prácticas

Cuando usamos librerías externas, es muy común declarar y usar un objeto global. Sin embargo, el precio a pagar es un escenario de pruebas complejo y, por supuesto, depender de un objeto global como por arte de magia no es una buena práctica.
¿Cómo le indicas a Angular sobre una librería externa declarada como global?
En mi ejemplo voy a usar la librería Leaflet, la clase InjectionToken y el decorador @Inject.
Si quieres leer más sobre el tema:
Instalar Leaflet
Instala el paquete de Leaflet y regístralo en angular.json para cargar la librería.
npm install leafletAbre el archivo angular.json y agrega los recursos leaflet.css y leaflet.js.
"styles": [
"src/styles.css",
"node_modules/leaflet/dist/leaflet.css"
],
"scripts": [
"node_modules/leaflet/dist/leaflet.js"
]
},
"configurations": { ...La API de Leaflet
Definimos el contrato con el objeto global para usar los métodos que ofrece Leaflet. Esto es opcional, pero hace que nuestro código sea más fácil de mantener y entender. Para lograrlo, crea una interfaz con los métodos públicos.
export interface LeafletAPI {
map(id:string):object;
setView(points: [], id:number): object;
tileLayer(url:string, options:object): object;
addTo(map:object):void;
}Usar la clase InjectionToken
Importa la clase InjectionToken desde @angular/core. Esta clase nos ayuda a crear una nueva instancia tipada con LeafletAPI y asociar el objeto global usando un identificador en texto. En el caso de Leaflet, el valor global es "L".
import { InjectionToken} from '@angular/core';
export let LEAFLET_TOKEN = new InjectionToken<LeafletAPI>('L');Proveer Leaflet
En el AppModule, declara una variable para L, registra el LEAFLET_TOKEN y asigna useValue: L dentro de los providers.
Ahora, Angular devolverá la instancia de L cada vez que algún servicio o componente solicite inyectar LEAFLET_TOKEN.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { LealefAPI, LEALEF_TOKEN } from './services/lealef.injector'; declare let L: LealefAPI;
@NgModule(
{
declarations: [ AppComponent ],
imports: [BrowserModule],
providers: [ { provide: LEALEF_TOKEN, useValue: L} ],
bootstrap: [AppComponent] })
export class AppModule { }Usar @Inject
El decorador @Inject() le indica a Angular qué objeto debe inyectar. Al usar nuestro token, el sistema de inyección de dependencias busca el valor que declaramos en los providers.
En nuestro caso, la clave es LEAFLET_TOKEN. Angular lo obtiene del provider registrado. Creamos un nuevo servicio llamado MapService y, en su constructor, declaramos la propiedad inyectando el token con @Inject.
import { Inject, Injectable } from '@angular/core';
import { LeafletAPI, LEAFLET_TOKEN } from './lealef.injector';
@Injectable()
export class MapService {
constructor(@Inject(LEAFLET_TOKEN) private _leaflet: LealefAPI) { }Leaflet queda inyectado en MapService mediante el inyector de dependencias de Angular, y ya podemos usar con seguridad los métodos definidos en LeafletAPI.
@Injectable()
export class MapService {
constructor(@Inject(LEAFLET_TOKEN) private _leaflet: LealefAPI) { }
showMenorca(): void {
let map = this._leaflef.map('mapid').setView([39.9255, 4.032], 13);
const tiles = this._leaflef.tileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{
maxZoom: 8,
minZoom: 3
}
);
tiles.addTo(map);
}
}
}¡Eso es todo!
Espero que esta guía te ayude a evitar el uso directo de objetos globales y a apoyarte en InjectionToken y @Inject. Si te gustó este artículo, compártelo.
Foto de Fernando @cferdo en Unsplash
Modern frontend development — Angular, React, TypeScript, accessibility, and performance.
Artículos Relacionados
Compartir este artículo
Si esta guía te resultó útil, compártela con tu equipo o con otros desarrolladores.
Software real. Lecciones reales.
Comparto las lecciones que aprendí por las malas, para que puedas evitarlas o estar preparado cuando ocurran.
Únete a 13,800+ desarrolladores y lectores.
Cero spam. Cancela tu suscripción en cualquier momento.