/ Angular

Configurar aplicación angular 5 basada en módulo

En la documentación oficial de angular 5 nos proponen dos forma de estructurar una aplicación, basada en módulos o en componentes.

Si tu aplicación es sencilla con una par de funcionalidades, sería suficiente crearla utilizando un módulo principal y todas sus características implementadas en componentes.

Si lo que pretendes es crear una aplicación escalable y que sea capaz de agregar funcionalidades fácilmente sin romperla, entonces, deberías de utilizar módulos.

Los módulos nos permiten crear aplicaciones modulares y escalable, ya sea con funcionalidades creadas por nosotros o por terceros. Cada módulo debe tener un objetivo único e independiente. Debe de ser capaz de desacoplar un módulo y que tu aplicación siga funcionando sin hacer un gran esfuerzo.

Requerimientos de la aplicación

Esta es una aplicación sencilla, la cual cuenta con 1 módulo principal, 2 módulos de funcionalidades y 2 módulos de configuración.

  • AppModule: Módulo principal de la aplicación.
  • LayoutModule: Lo utilizaremos para crear el layout de la parte privada de la aplicación.
  • LibroModule: Encargado de la gestión de Libros.
  • AutorModule: Encargado de la gestión de Autores.
    En el desarrollo de este tutorial utilizaremos angular cli para generar módulos y componentes, si no estás familizado con angular cli, puedes revisar el tutorial anterior donde se explica la configuración y utilización de angular cli

Generar nueva aplicación con angular cli.

Para generar la estructura principal de la aplicación, utilizaremos el comando ng new de angular cli.

ng new BookDirectory --routing=true --prefix=gp --inlineStyle=true --inlineTemplate

Al ejecutar la línea anterior, tendremos nuestro proyecto ‘BookDirectory‘ con la siguiente estructura.

BookDirectory
    ├── README.md
    ├── e2e
    │   ├── app.e2e-spec.ts
    │   ├── app.po.ts
    │   └── tsconfig.e2e.json
    ├── karma.conf.js
    ├── package.json
    ├── protractor.conf.js
    ├── src
    │   ├── app
    │   │   ├── app-routing.module.ts
    │   │   ├── app.component.spec.ts
    │   │   ├── app.component.ts
    │   │   └── app.module.ts
    │   ├── assets
    │   ├── environments
    │   │   ├── environment.prod.ts
    │   │   └── environment.ts
    │   ├── favicon.ico
    │   ├── index.html
    │   ├── main.ts
    │   ├── polyfills.ts
    │   ├── styles.css
    │   ├── test.ts
    │   ├── tsconfig.app.json
    │   ├── tsconfig.spec.json
    │   └── typings.d.ts
    ├── tsconfig.json
    └── tslint.json

Los archivos que nos interesan están dentro de la carpeta src, es donde encontraremos los archivos de nuestra aplicación y donde estaremos trabajando constantemente.

Si quieres conocer la funcionalidad de cada unos de los directorios/archivos generados por angular cli, visita la documentación oficial.

src
├── app
│   ├── app-routing.module.ts
│   ├── app.component.spec.ts
│   ├── app.component.ts
│   └── app.module.ts
├── assets
├── environments
│   ├── environment.prod.ts
│   └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
├── test.ts
├── tsconfig.app.json
├── tsconfig.spec.json
└── typings.d.ts

Si ejecutamos ng server dentro del directorio de nuestra aplicación obtendremos este resultado.

previsualizacion-inicail-aplicacion

En AppComponent importamos AppRoutingModule, que cargará LayoutModule de forma asíncrona.

¿Porque de forma asíncrona? Una de las ventajas de trabajar con módulos, es que nos permiten cargar las funcionalidades de nuestra aplicación bajo demanda. Esto ayuda a disminuir el tiempo de inicio de la aplicación, algo que es muy importante.

¿Como hacemos esto? vamos a ello…

Configurar módulo principal LayoutModule

Para generar LayoutModule utilizaremos el siguiente comando.

ng g m layout --routing

Ahora la carpeta app, tendrá la siguiente estructura:

src/app
├── app-routing.module.ts
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
└── layout
 ├── layout-routing.module.ts
 └── layout.module.ts

Por ahora sólo hemos generado el módulo. Ahora crearemos LayoutComponent que será el componente por defecto del módulo.

Generar y configurar LayoutComponent

ng g c layout/layout --flat --inlineTemplate --inlineStyle

agregar_layout_component
Al ejecutar el comando anterior, se genera LayoutComponent y es agregado de forma automática en la propiedad declarations:[] de LayoutModule.

Configurar ruta por defecto en LayoutRoutingModule

La idea es que cuando sea llamado LayoutModule, este cargue LayoutComponente, para ello debemos configurar la ruta por defecto de este módulo.

Dentro de layput-routing.module.ts agregamos {path: '', component: LayoutComponent} dentro del array de rutas. Dejando el valor de path: '' vacío,de esta forma obliga la carga de este componente cuando es llamado LayoutModule.

Debería de quedar de la siguiente forma.

// layput-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { LayoutComponent } from "./layout.component";

const routes: Routes = [
  {path: '', component: LayoutComponent}
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class LayoutRoutingModule { }

Registrar LayoutModule como módulo por defecto de la aplicación.

Aún 'LayoutModule' no esta siendo utilizado en la aplicación, para utilizarlo debemos llamarlo desde el archivo 'app-routing.module.ts' llamándolo en la ruta por defecto.

// app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  {
    path: '',
    loadChildren: './layout/layout.module#LayoutModule'
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Si ejecutamos la aplicación nuevamente ng server debería de mostrar el contenido del template definido en LayoutComponent.
configurado-layout-module
Como podemos ver, al llamar la ruta /, esta llama a LayoutModule que a su vez llama a LayoutComponent para que muestre su contenido.

Ahora todos los módulo de nuestra aplicación, se deben cargar desde layout-routing.module.ts definiendo las rutas en la propiedad children de la ruta por defecto. De esta forma conseguimos cargar el contenido de cualquier módulo dentro de LayoutComponent.

Ya tenemos configurado el módulo por defecto de aplicación, ahora crearemos los componentes encargados de la estructura: MainHeaderComponent, MainContentComponent.

Es un poco complicado de entender la carga de módulo y componentes y más si estás empezando. Te recomiendo instalar Augury, es una extención para chrome, la cual te muestra la estructura de rutas y componentes de una aplicación angular.
auguri

En la imagen anterior, puedes notar como AppComponent contiene router-outlet y dentro de este se carga LayoutComponent. Esta extensión seguro te ayuda a entender más fácil como estamos cargando los módulos y componentes.

Crear main-header y main-content component.

MainHeaderComponent: Representa la cabecera de la aplicación, donde alojaremos las opciones del menú.

ng g c layout/MainHeader

MainContentComponent: Es el componente donde cargaremos el contenido de los módulos de la aplicación.

ng g c layout/MainContent --inlineTemplate --inlineStyle

En el template de MainContentComponent, agregamos la directiva es donde se cargará el contenido de nuestra aplicación.

Modifica el archivo main-content.component.ts y pega el siguiente código.

import { Component } from '@angular/core';

@Component({
  selector: 'gp-main-content',
  template: `<router-outlet></router-outlet>` , 
  styles: [] }) export class MainContentComponent { }

Modificamos el archivo en layout.component.ts agregando las directivas gp-main-header y gp-main-content en su propiedad template.

import { Component } from '@angular/core';

@Component({
  selector: 'gp-layout',
  template: `
    <gp-main-header></gp-main-header> 
    <gp-main-content></gp-main-content>`
})
export class LayoutComponent {}

Por último modificamos el archivo app.component.ts con el siguiente código.

import { Component } from '@angular/core';

@Component({
  selector: 'gp-root',
  template: `<router-outlet></router-outlet>`,
  styles: []
})
export class AppComponent { }

Con esto ya tenemos la estructura básica de la aplicación definida. Si visualizamos la aplicación en el navegador e inspeccionamos con Augury, tendremos lo siguiente.

Estructura de módulos de la aplicación

Como podemos ver, AppComponent está cargando LayoutComponent y este a su vez está cargando MainHeaderComponent y MainContentComponent.

Ahora todos los módulos de características agregados en nuestra aplicación deben configurar sus rutas en el módulo layout-routing.module.ts en la propiedad children de la ruta predeterminada.

Configurar módulo Libros

Este módulo se encargará de la gestión de libros, por ahora crearemos el módulo y su componente principal, además de configurar sus rutas.

ng g m libro --routing

Generamos el componente principal de este modulo:

ng g c libro/libro --flat --inlineTemplate --inlineStyle

Ya tenemos nuestro LibrosModule creado, además de su componente principal.

src/app/libro
├── libro-routing.module.ts
├── libro.component.spec.ts
├── libro.component.ts
└── libro.module.ts

Configurar ruta predeterminada de LibrosModule

Modificamos el archivo libro-routing.module.ts con el siguiente código:

libro-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { LibroComponent } from "./libro.component";

const routes: Routes = [
  {path: '', component: LibroComponent}
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class LibroRoutingModule { }

Ahora cuando sea llamado el módulo LibroModule, se cargará LibroComponent por defecto.

Configurar la ruta para cargar LibroModule.

Esta configuración la debemos agregar en el archivo layout-routing.module.ts que carga por defecto LayoutComponent, que contiene la directiva router-outlet. Por tanto todas las rutas que deseemos cargar dentro de layout, deben ser hijas de esta ruta principal.

Por esta razón utilizaremos la propiedad childrens: [], quedando el archivo de rutas configurado de la siguiente forma.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { LayoutComponent } from "./layout.component";

const routes: Routes = [
  {path: '', component: LayoutComponent, children:[
    {
      path: '',
      loadChildren: '../libro/libro.module#LibroModule'
    }
  ]}
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class LayoutRoutingModule { }

Si te fijas la propiedad path está vacía, esto lo hago para que este módulo sea cargado de forma predeterminada en LayoutModule, si agrego un nombre a esta ruta, no se cargará de forma automática, si no que, tendría que invocarla mediante un enlace utilizando routerLink='nombre-ruta'

Con esto ya tenemos anidado LibroModule dentro de LayoutModule.

Pon en práctica lo explicado hasta ahora, generando un módulo llamado autor siguiendo los siguientes pasos.

  1. Genera el módulo: ng g m autor
  2. Genera el componente principal del módulo. ng g c autor/autor --flat -it -is
  3. Registra la ruta predeterminada del módulo.
const routes: Routes = [
  {path: '', component: AutorComponent}
];
  1. Registra una ruta para el móduto, dentro de `layout-routing.module.ts``
{
   path: 'autores',
   loadChildren: './autor/autor.module#AutorModule'
}

Si has tenido algún inconveniente al general el módulo autor, puedes ver el código en el repositorio de GitHub.

Vincular ambos módulos desde el MainHeaderComponent

Ya tenemos dos módulos de características configurados, ya podemos agregar algunos vínculos en el MainHeaderComponent especificamente en su template main-header.component.html.

<a [routerLink]="['/']">Libros</a>
<a [routerLink]="['/autores']">Autores</a>

Esta es la estructura actual de la aplicación:

src/app
├── app-routing.module.ts
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── autor
│   ├── autor-routing.module.ts
│   ├── autor.component.spec.ts
│   ├── autor.component.ts
│   └── autor.module.ts
├── layout
│   ├── layout-routing.module.ts
│   ├── layout.component.spec.ts
│   ├── layout.component.ts
│   ├── layout.module.ts
│   ├── main-content
│   │   ├── main-content.component.spec.ts
│   │   └── main-content.component.ts
│   └── main-header
│       ├── main-header.component.css
│       ├── main-header.component.html
│       ├── main-header.component.spec.ts
│       └── main-header.component.ts
└── libro
    ├── libro-routing.module.ts
    ├── libro.component.spec.ts
    ├── libro.component.ts
    └── libro.module.ts

Conclusión

Hemos logrado configurar los módulos principales de la aplicación, además de sus rutas ubicadas en archivos independientes.

El siguiente paso será crear la estructura visual de la aplicación para ir dándole funcionalidad.

En el próximo tutorial, agregamos bootstrap 4 a nuestra aplicación, habilitaremos el uso de SCSS, ya que no lo hicimos al generar la aplicación.

Además, crearemos el menú principal utilizando bootstrap 4. Agregaremos datos de ejemplo en cada uno de los módulos para poder visualizar la estructura final de la aplicación.

Hasta el proximo…