Creando módulos

Hemos visto como crear componentes que nos permiten atomizar el diseño de nuestra aplicación. Hemos crado un componente para la cabecera de la página, y también podríamos haber creado, por ejemplo, un pie de página. De hecho, cuando aprendamos sobre enrutamiento crearemos un componente que será una barra de navegación, y lo incorporaremos, por ejemplo, a la cabecera de la página.

Por supuesto, crear componentes no sólo nos permite dividir el viewport del navegador de forma visual. Los componentes pueden crearse para dividir la aplicación desde el punto de vista de las funcionalidades. Y es aquí donde entran en juego los módulos. Se trata de tener las funcionalidades lo más compartimentadas y desacopladas que la lógica exija, de modo que siempre tengamos claro qué hace cada parte de nuestra aplicación. Para ello, creamos módulos que, como sabes, encapsulan a los componentes. Así, una aplicación de gestión comercial, por ejemplo, tendría un módulo para gestión de clientes, otro para facturación, otro para almacén, etc. Y cada uno tendría sus propios componentes con funcionalidades específicas como ver detalles, listar elementos, etc.

Lo mejor de esto es que los módulos pueden comunicarse entre sí, pasando datos de unos a otros e, incluso, podemos renderizar en el navegador, simultáneamente, componentes de distintos módulos. Por ejemplo, en una aplicación de gestión, podemos necesitar ver un artículo del almacén y su stock (lo que vendría de componentes del módulo de almacén) y las ventas de ese artículo que se han hecho, lo que podría venir del módulo de facturación.

Lo importante de todo esto es tenerlo todo desacoplado, de modo que, por mucho que crezca o evolucione nuestra aplicación, sea mantenible y sepamos, siempre, qué módulos pueden pasar datos a otros, cuales no pueden hacerlo, donde está cada cosa… Vamos a ello.

PREPARANDO EL ESCENARIO

Para esta fase de nuestro aprendizaje vamos a crear una nueva aplicación Angular 5. La vamos a llamar angular02 y la vamos a crear, como ya sabemos, situándonos en la terminal de mandatos, en el directorio raíz de nuestro localhost, y tecleando el comando siguiente:

ng new angular02 -p a02 --routing true

Una vez creada vamos a «preparar» la base para empezar a trabajar con una estructura basada en módulos. Para ello, empezamos modificando, como ya sabemos, el fichero package.json, para que la compilación se efectúe Ahead of Time y que, al iniciar el servidor de Angular arranque el navegador y cargue la aplicación, cambiando "start": "ng serve", por "start": "ng serve --aot -o",. Como esto lo haremos ya siempre, no volveremos a mencionarlo en posteriores ocasiones.

También instalaremos jQuery y Bootstrap, tecleando en la terminal de VSC, dentro del directorio de nuestra aplicación, los comandos que ya conocemos para esto: npm i jquery --save y npm i bootstrap --save (de momento, como estamos en fase de desarrollo en pruebas, nos da un poco igual que se instale bootstrap 4; ya entraremos en esos detalles más adelante). Vemos que las dos librerías recién instaladas aparecen ahora referenciadas en package.json y, además, se encuentran dentro de la carpeta node_modules.

Si te acuerdas de lo que hicimos con la aplicación anterior (y si no te lo recuerdo yo ahora), necesitamos referenciar las librerías externas que acabamos de instalar en .angular-cli.json, a fín de que puedan ser usadas por la aplicación que vamos a construir. Para ello, tenemos que modificar las claves styles y scripts de este fichero. Nos quedarán así:

Lo siguiente que vamos a hacer es modificar el fichero de la vista de AppComponent, que es el componente de inicio de la aplicación, como ya sabemos. Quitamos el contenido que viene por defecto, manteniendo, únicamente, la etiqueta final <router-outlet></router-outlet>. Dentro de la carpeta src/app/ modificamos app.component.html, para que nos quede así:

En app.component.ts eliminamos la variable title, que, por ahora, no nos va a hacer falta. Nos queda así:

Y ya está preparado el escenario de trabajo. La cabecera que teníamos en la anterior aplicación no la vamos a crear aquí, sino en otra parte.

CREANDO UN MÓDULO

Cómo hemos dicho, los componentes (y otras cosas que ya veremos) se encapsulan, o agrupan en módulos. Vamos a ver cómo crear esos módulos. Empezaremos por crear un módulo al que llamaremos commons, en el que luego alojaremos los componentes y otros elementos que serán comunes a toda la aplicación (como cabecera de página, barra de navegación, pie de página, y otros). Para crear este módulo podemos usar el siguiente comando:

ng generate module commons

o, abreviadamente:

ng g m commons

Sin embargo, nosotros vamos a ir un poco más allá. Vamos a crear el módulo con su propio sistema de enrutamiento, preveyendo que, dentro de muy poco, vamos a necesitarlo, así que usaremos el siguiente comando:

ng g m commons --routing

La terminal de mandatos nos responde, tras unos segundos, así:

create src/app/commons/commons-routing.module.ts (249 bytes)
create src/app/commons/commons.module.ts (279 bytes)

Esto nos informa, como ya sabemos, de los cambios que se han producido en la estructura de la aplicación. En concreto, dentro del directorio src/app/ se ha creado un directorio con el nombre del módulo. Dentro de este se ha creado el archivo base para el módulo, cuyo nombre está formado por el nombre del módulo, un punto, la partícula module y la extensión .ts (commons.module.ts). Además, como al crearlo, le pedimos que lo dejara preparado para enrutamientos, se ha creado otro archivo con el nombre del módulo, seguido de -routing.module.ts.

La envolvente del módulo (commons.module.ts) tiene una estructura que ya nos suena familiar:

En las líneas de la 1 a la 4 tenemos las importaciones, de la 6 a la 12 el decorador y en la 13 la exportación de la clase, para poder usarlo desde otros puntos de nuestra aplicación. En seguida veremos como usarlo.

MUCHA ATENCIÓN. Observa que hemos creado el módulo con el nombre commons. Esto es algo con lo que debes tener mucho cuidado. Cuando crees un módulo, o un componente, y utilices para la nomenclatura nombres en inglés (lo que es una práctica muy habitual y aconsejable en desarrollo) es posible que se produzcan colisiones. Por ejemplo, si a nuestro módulo, en lugar de commons lo hubiéramos llamado common, el nombre estaría entrando en colisión con el CommonModule del propio Angular, y tu aplicación no funcionaría nunca. Si tienes dudas, puedes preceder tus nombres con el prefijo de la aplicación (por ejemplo, a02commons no te daría ningún conflicto). Es muy importante evitar las colisiones de nombres. De este tema ya hablamos respecto a la nomenclatura de los componentes en este artículo, pero insisto en elllo aquí, por la importancia que tiene.

CREAR UN COMPONENTE DENTRO DE UN MÓDULO

En un artículo anterior vimos como crear un componente que se generaba, por defecto, en el AppModule (que era el único módulo que teníamos entonces). Ahora vamos a crear un componente dentro de un módulo específico. En concreto, dentro del módulo commons que acabamos de crear vamos a generar un componente llamado header, donde haremos una cabecera que estará disponible para todas las vistas de la aplicación. Lo hacemos con el siguiente comando:

ng g c commons/header --export

El flag --export le dice al CLI que el componente debe ser exportable, para poder usarlo en otros módulos de la aplicación. Por lógica, cualquier componente que esté en un módulo de «cosas comunes» debería ser exportable.

Tras unos segundos, la terminal nos responde con:

create src/app/commons/header/header.component.html (25 bytes)
create src/app/commons/header/header.component.spec.ts (628 bytes)
create src/app/commons/header/header.component.ts (269 bytes)
create src/app/commons/header/header.component.css (0 bytes)
update src/app/commons/common.module.ts (385 bytes)

Vemos que se han creado cuatro ficheros en la ruta correspondiente, y se ha modificado el commons.module.ts, así:

Ahora vamos a retocar la cabecera de vistas (el componente commons/header) para que nos quede visualmente clara, usando, incluso, clases de Bootstrap. En primer lugar, modificamos la vista en header.component.html, así:

Ahora modificamos el archivo de estilos, header.component.css, así:

Como ves, le hemos dado a la clase de bootstrap un poco de color (en lugar del gris pálido que se ponen por defecto), para que veamos más claros los resultados luego. Y, por ahora, lo dejamos así. No vamos a meter más cambios en la cabecera.

VISIBILIDAD DEL COMPONENTE

Ya tenemos un componente creado dentro de un módulo. El componente puede ser para ver y utilizar sólo desde dentro del módulo donde lo hemos creado, o para poder emplearlo desde otros módulos. En nuestro caso, como hemos creado una cabecera de página, dentro de un módulo que hemos detinado a componentes comunes, sí vamos a querer que se pueda ver desde otros componentes situados en el mismo módulo, o en otros módulos. Y, para concretar un poco lo que pretendemos hacer, queremos que, desde AppComponent (que está en AppModule y define la vista principal de nuestra aplicación) podamos cargar la cabecera definida en HeaderComponent, dentro de CommonsModule.

Para lograr esto tenemos que seguir los pasos que vamos a detallar a continuación:

Lo primero es definir que el componente sea exportable. Esto se hace en commons.module.ts, cuyo listado actual es el que aparece un poco más arriba. Observa las líneas 5, 12 y 13, donde el módulo importa el componente, lo incluye en la clave declarations y, finalmente, en la clave exports. Como ocurre que, al crear el componente, le añadimos el flag --export, estas líneas se han creado automáticamente. Si no hubiéramos usado este flag, tendríamos que escribirlas a mano.

El siguiente paso es importar el módulo CommonsModule en AppModule, que es donde lo queremos usar. Observa las líneas resaltadas en el listado de app.module.ts:

Con esto le estamos diciendo a AppModule que debe importar el módulo CommonsModule. Como en este ya tenemos el HeaderComponent definido como exportable, resulta que desde AppModule ya se puede ver el componente que nos interesa.

Por último, sólo nos resta ir a la vista de AppComponent (app.component.html) e incluir una etiqueta de apertura y cierre con el valor de la propiedad selector de header.component.ts, para indicarle a Angular que debe cargar ese componente, en el punto que le digamos. Quedará así:

Observa la primera línea del código.

Ahora es el momento de arrancar el servidor de Angular. Si lo tenías arrancado, seguramente estés viendo que da errores, debido a que, como ya sabemos, la compilación AoT no funciona automáticamente cuando se crea un componente nuevo (ya lo hemos visto en un artículo anterior), Tampoco funciona automáticamente cuando se hace una importación de un componente de otro módulo. Así pues, si tienes en marcha el servidor, interrúmpelo (Ctrl-C) y vuelve a ponerlo en marcha (npm start).  Verás que se carga la aplicación con la cabecera de HeaderComponent y el contenido de AppComponent como se ve a continuación:

Observa que debajo de la cabecera no hay nada, porque estamos visualizando el AppComponent y le hemos limpiado todo el HTML.

ATENCIÓN. Es muy importante tener claras las diferencias cuando creamos un componente como exportable o como no exportable, por una razón. Tú puedes crear un componente como no exportable y darte cuenta, posteriormente, de que necesitas hacerlo exportable para verlo desde otros módulos. Recuerda que un componente no exportable sólo será visible desde su propio módulo.

Si has creado un módulo llamado, por ejemplo Modulo01 con dos componentes llamados Componente01 (exportable) y Componente02 (no exportable), Componente01 se podrá ver desde Modulo01 y desde cualquier otro módulo que importe Modulo01, mientras que Componente02 sólo será visible desde Modulo01. Si ahora quieres verlo desde otros módulos, tienes que hacerlo exportable. La forma de hacerlo es ir al TypeScript de Modulo01, llamado modulo01.module.ts y asegurarte de incluir el nombre de Componente02 en la propiedad exports: del decorador.

Además, donde queramos poder usar los componentes de Modulo01 tenemos que importar dicho módulo. Por ejemplo, imagina que quieres usar el componente Componente01 (que pertenece a Modulo01) desde Modulo02. Tienes que ir al TypeScript de Modulo02, llamado modulo02.module.ts y añadir el nombre Modulo01 en la propiedad imports: del decorador. Si tienes VSC configurado con las extensiones que te comenté en este artículo, encima del decorador se incluirá, automáticamente, una línea que importará el módulo. Algo así como:

import { Modulo01 } from './modulo01/modulo01.module';

Si no tienes configurado el editor, o estás usando otro que no incluya autoimportaciones, esta línea tendrás que ponerla a mano, asegurándote de teclear la ruta correcta. Por eso te insisto en usar VSC con las extensiones que uso yo. Es muy cómodo y seguro.

ATENCIÓN. Cuando estás usando el servidor de Angular con la opción --aot (cómo hacemos nosotros), un componente de un módulo te resultará visible en otro módulo en las pruebas durante el desarrollo aunque no lo hayas exportado como te indico aquí. Sin embargo, cuando aprendamos a desplegar la aplicación para producción, verás que te surgen problemas si los componentes no están correctamente exportados. Por lo tanto, no te olvides de hacer exportables los componentes que necesites en otros módulos, aunque te parezca que, de momento, es innecesario. Si tienes dudas, arranca, temporalmente, el servidor sin --aot y si hay algún error, tu aplicación no funcionará y verás los detalles del problema en la consola del navegador. Luego, una vez solucionados, vuelve a activar el --aot.

CONCLUYENDO

En este artículo hemos visto como crear módulos en Angular, lo que nos permite organizar mejor los contenidos. También hemos aprendido a crear componentes en los nuevos módulos, y a hacerlos exportables, para que los componentes de un módulo puedan ser usados en otro. Estamos dando pasos cada vez más relevantes en la dirección de aprender a crear aplicaciones con Angular. En el próximo artículo seguiremos aprendiendo cosas interesantes que nos darán, cada vez, mayores habilidades. La aplicación que estamos usando, en su estado actual, la tienes en este enlace. Recuerda, una vez descomprimida en tu directorio angular02, ejecutar npm install, como te comenté al final de este artículo. Si no, no te funcionará.

   

Deja un comentario