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.
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
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
.
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.
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.
- Genera el módulo:
ng g m autor
- Genera el componente principal del módulo.
ng g c autor/autor --flat -it -is
- Registra la ruta predeterminada del módulo.
const routes: Routes = [
{path: '', component: AutorComponent}
];
- 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…