Arquitectura de layouts

Foto de Sahand Babali en Unsplash

Cuando se inicia un proyecto de Angular siempre surge la pregunta sobre qué estructura de carpetas debe tener. No es fácil la respuesta dado que depende de muchos factores como por ejemplo si es solamente una PoC, si se crearán librerías, si participan varios desarrolladores/equipos, y un largo etcétera.

Quizás empiece siendo un proyecto generado automáticamente mediante Angular CLI y que a lo largo de su vida irá transformándose según las necesidades pero lo ideal sería empezar con una buena base y que sea escalable.

En este artículo, vamos a centrarnos bajo el punto de vista de la interfaz de usuario (UI) y más concretamente en la arquitectura de layouts o estructura de las «vistas» (el HTML). Imagínatelo como si fuera un diseño wireframe lleno de «cajitas» vacías donde poner componentes.

Problemática

Cuando en un proyecto intervienen varios desarrolladores/equipos, cada persona programará según su aprendizaje/experiencia pero obligatoriamente deberá seguir alguna línea de estilos o un “Design System”.

Aún siguiendo dicha guía, la estructura del HTML puede crearse de diferentes maneras como por ejemplo dónde mostrar los datos en una modal (título, cuerpo y pie) ó en un artículo (título y cuerpo) e incluso en la propia estructura de la página de inicio (cabecera, navegación, artículo, pie, …).

No se desea restringir la creatividad de un desarrollador, simplemente se pretende posicionar de forma correcta las diferentes partes o secciones de la vista de un componente en un layout específico.

Solución

Para solucionar esa problemática nos basaremos en la proyección de contenidos con placeholders. Es decir, crearemos un tipo de componente específico para cada layout siendo de tipo presentacionales sin estado.

De esta manera tenemos algunas ventajas como:

La forma de proceder sería la siguiente:

  1. Se establecen unos layouts para cada situación: Principal/Inicio de la aplicación, artículo, modal, …
  2. Los desarrolladores/equipos crean su componente indicando qué layout necesita y a qué parte del layout tiene que ir esa parte de código (placeholder).

Librería de layouts

Vamos a crear una librería de layouts (@af/layouts) en vez de crear una carpeta «layouts» dentro de la aplicación. De esta manera la librería siempre se puede reutilizar en otros proyectos.

Layout principal

Creamos un layout principal (main) que dispondrá de los elementos de la siguiente manera:

Main Layout

Resultando el código del componente de la siguiente manera:

HTML del componente (main.component.html):

<div class="wrapper">
    <header><ng-content select="[header]">Cabecera</ng-content></header>
    <article><ng-content select="[article]">Artículo</ng-content></article>
    <nav><ng-content select="[nav]">Navegación</ng-content></nav>
    <footer><ng-content select="[footer]">Pie</ng-content></footer>
</div>

TS del componente (main.component.ts):

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { CommonModule } from '@angular/common';


@Component({
    selector: 'af-main-layout',
    standalone: true,
    imports: [CommonModule],
    templateUrl: './main.component.html',
    styleUrl: './main.component.scss',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class MainLayoutComponent {}

Estilos del componente (main.component.scss):

.wrapper {
    display: grid;
    grid-template-areas:
        "header header header"
        "nav article article"
        "footer footer footer";
    grid-template-rows: 80px 1fr 50px;
    grid-template-columns: 10% 2fr;
    gap: 2px;
    height: 100vh;
    margin: 0;
}

header,
footer,
article,
nav {
    padding: 1em;
    background: #bae0e2;
}
header {
    grid-area: header;
}
footer {
    grid-area: footer;
}
article {
    grid-area: article;
}
nav {
    grid-area: nav;
}

/* Stack the layout on small devices/viewports. */
@media all and (max-width: 575px) {
    .wrapper {
        grid-template-areas:
            "header"
            "nav"
            "article"
            "footer";
        grid-template-rows: 80px 50px 1fr 50px;
        grid-template-columns: 1fr;
    }
}

De esta manera si se desea disponer de diferente manera los elementos, basta o bien cambiando la estructura HTML o cambiar los estilos CSS del layout.

Así para la página inicial dentro de la aplicación, solo hay que usar el «main-layout» y posicionar los diferentes componentes. 

Nota: como aquí el selector se hace mediante atributo select="[header]", pero se puede indicar mediante el tag,  identificadores, o nombres de clases CSS.

Así, en el componente root (app.component.html) de la aplicación, utilizamos el «main-layout», diciéndole qué componente va a qué sección:

<af-main-layout>
    <af-header header></af-header>
    <af-navigation nav></af-navigation>
    <af-footer footer></af-footer>
    <af-articles article></af-articles>
</af-main-layout>

Layout article

Otro ejemplo sería el de layout de un artículo, que podemos definir su layout como:

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
    selector: 'af-article-layout',
    standalone: true,
    imports: [CommonModule],
    template: `
<h2><ng-content select="[title-section]">article title</ng-content></h2>
<div>
    <ng-content select="[body-section]">body title</ng-content>
</div>

`,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class ArticleLayoutComponent {}

Y para crear artículos con este layout debería ser:

<af-article-layout>
    <ng-content title-section>Artículo 1</ng-content>
    <ng-content body-section>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
        commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
        velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
        occaecat cupidatat non proident, sunt in culpa qui officia deserunt
        mollit anim id est laborum.
    </ng-content>
</af-article-layout>

Si el día de mañana, por ejemplo, en vez de que el título de los artículos sea un h2, sea un h3, solo hay que modificar el layout y no los artículos.

Resumen

Hemos visto como dividir un layout en secciones usando la proyección de contenidos de Angular para que cada desarrollador coloque parte de su vista en la sección apropiada. De esta manera evitamos que puedan existir diferentes estructuras dado un mismo concepto. Si asignáramos un responsable de los layouts, éste recaería sobre el diseñador que sería la persona encargada de crear nuevos layouts, mover de sitio las secciones, eliminarlas, añadir nuevas, etc.

¿Qué te ha parecido esta división de las vistas? Puedes ver el ejemplo en el repositorio de github.

Entradas relacionadas

Storybook en Nx Angular monorepo: Instalación

por César Marín
9 meses atrás

¿Cómo migrar de AngularJS a Angular?

por César Marín
6 años atrás

Storybook en Nx Angular monorepo: Configuración

por César Marín
9 meses atrás
Salir de la versión móvil