Cómo construir un tema básico con Angular Material

Manuel García18-Feb, 2020

Existen diferentes herramientas o librerías de estilos que ayudan a la creación de temas con Angular. Una de las librerías más famosas es Angular Material, que sigue las pautas de Material Design, la guía de estilo creada por Google para el sistema operativo Android.

Esta librería trabaja con múltiples componentes donde cada uno de ellos dispone de una API de referencia donde poder consultar la forma de utilización, su estilo, ejemplos de utilización, etc. Su documentación es su punto fuerte y hace muy fácil su utilización e implantación en cada proyecto donde se quiera mejorar el aspecto con una capa de estilos de referencia como es Material Design.

Dispone de múltiples componentes, prácticamente todos los que una web común pueda necesitar: tarjetas (cards), listas, botones, tablas, etc.

En este artículo se detalla el proceso de instalación de Angular Material así como varios ejemplos de utilización de componentes, hasta conseguir el aspecto de un tema o plantilla básica.

Angular Material: instalación

Nota: La versión de Angular utilizada en este artículo es la 9.0.1

Para la instalación y utilización de Angular Material, tan solo será necesario tener un proyecto Angular ya iniciado, y la librería se instalará como dependencia.

Programando en Angular

Instalación Angular

Programando con Angular Material

Añadir Angular Material al proyecto de Angular

Al ejecutar el comando anterior, aparece una lista de opciones de temas base o bien elegir la opción de tema personalizado mediante la elección de la opción “Custom”. La diferencia entre un tema base o la personalización es que si se elige un tema base de ejemplo, se añadirá al proyecto un archivo CSS con estilos predefinidos para todos los componentes, mientras que si se elige la opción “Custom”, tocará definir estilos globales y personalizar los componentes en base a las necesidades específicas. Para este artículo se elige la opción “Custom” para ilustrar cómo se realiza un tema desde cero.

Código de Angular Material

Elección “Custom” para creación del tema

A las siguientes preguntas, sobre generalizar los estilos de tipografía e importar las animaciones, contestar SÍ (Yes). Esta última opción hará que importe en el archivo app.module.ts el módulo BrowserAnimationsModule.

Código de Angular

Instalación de Angular Material finalizada

Utilización de componentes

Una vez ya instalado Angular Material, se echa un vistazo a la documentación para ver qué componentes serán necesarios para el tema que se quiere hacer. En este artículo, se usan diversos componentes de ejemplo.

Para formar la estructura visual de la plantilla, se utilizarán dos columnas, siendo la primera el menú lateral (sidemenu) típico de una aplicación web interna o “admin site”. Para esta solución, Angular Material incorpora un componente llamado “mat-sidenav”, por lo que simplemente hay que importar el módulo asociado (MatSidenavModule) en el componente principal (app.component.html) y darle los estilos visuales que se consideren. Al agregar el componente en cuestión, ya tendrá estilos por defecto, pero éstos son limitados (ya que se eligió en su momento el tema “Custom”) así que se le da algunos estilos básicos. También se añade en este componente principal el componente de Angular Material “mat-toolbar” que proporciona una cabecera. Este componente permite añadir texto y/o diferentes elementos tales como iconos, enlaces, etc. tal y como una cabecera o header de una aplicación móvil al uso.

En el menú lateral también se incorpora una lista de elementos que servirá de menú de enlaces, para dar de alta diferentes páginas con diferentes componentes cada uno.

imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatToolbarModule,
    MatSidenavModule,
    MatMenuModule,
  ],

Importación de módulos necesarios módulo menú lateral y cabecera (app.module.ts)

Una vez importados los módulos, es posible utilizarlos en la vista (.html):

<mat-sidenav-container class="container">

 <!-- side-nav -->

 <mat-sidenav mode="side" opened class="sidenav">

 <mat-toolbar class="toolbar">D55</mat-toolbar>

 <!-- Elements list menu -->

 <mat-list>

 <mat-list-item *ngFor="let item of links"> 

 <a matLine [routerLink]="item.url">{{ item.name }}</a>

 </mat-list-item>

 </mat-list>

 </mat-sidenav>

 <!-- side-nav-content -->

 <mat-sidenav-content>

 <mat-toolbar class="toolbar">

 <mat-toolbar-row>

   <span>Angular Material Example</span>

 </mat-toolbar-row>

 </mat-toolbar>

 <router-outlet></router-outlet>

 </mat-sidenav-content>

</mat-sidenav-container>

Código HTML con menú lateral y cabecera (app.component.html)

El código HTML consta de un bucle (*ngFor) de los links necesarios del menú. Éstos se definen en la clase del componente (app.component.ts) para, posteriormente, recorrerlos y mostrarlos dinámicamente:

links = [
    {
      name: "Inicio",
      url: ""
    },
    {
      name: "Lista",
      url: "list"
    },
    {
      name: "Formulario",
      url: "form"
    }
  ]

Lista de links del menú (app.component.ts)

Y dar unos estilos básicos con código SASS:

$whiteColor: white;
$d55Color: #FF3366;

.container{
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  
  .sidenav{
    background-color: $d55Color;

    .toolbar{
      color: $d55Color;
      background-color: $whiteColor;
      display: flex;
      justify-content: center;
    }

    /*
    * Navigation
    */
    .mat-list-item a{
      color: $whiteColor;
      text-decoration: none;
    }
  }

  .mat-sidenav-content{
    .toolbar{
      color: $whiteColor;
      background-color: $d55Color;
    }
  }
}

Código CSS del componente principal (app.component.html)

Código CSS del componente principal

Imagen del aspecto visual (sin contenido – parte derecha)

Una vez definido el esqueleto del tema, con su menú lateral y su cabecera con título, queda establecer el formato de rutas, y hacer que en la parte derecha se muestre el contenido de la página del menú que se haya elegido. Evidentemente, antes se deberán haber creado las páginas (componentes) que se quieran incorporar al menú:

Generate component en Angular Material

const routes: Routes = [
  { path: '', component: HomeComponent, data: { title: 'Home' } },
  { path: 'list', component: ListComponent, data: { title: 'List' } },
  { path: 'form', component: FormComponent, data: { title: 'Form' } }
];

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

Listado de rutas definidas (app-routing.module.ts)

Home

Esta página debería ser lo que en un tema basado en una admin page sería la página de dashboard. Por simplificar, ya que en las otras dos páginas sí se meterán componentes, aquí solo se pondrá un título, sin darle más importante. Esta página solo actúa de página inicial en las rutas definidas.

<h2>Bienvenida</h2>

Título de la página principal (home.component.html)

Lista

En el menú ya se ha utilizado una lista, por lo que para el proyecto ya estaría importado desde el módulo principal (app.module.ts), y se podría usar sin problema en otro componente angular. Al haber varios tipos, en esta página se utiliza a modo de ejemplo un tipo de lista distinto: Lista con selección. La propia documentación de Angular Material incorpora muchos otros ejemplos: Lista con iconos, con avatar, multilínea, etc.

frameworks: string[] = ['Angular', 'React', 'Vue', 'Ionic', 'Flutter', 'React Native'];

Listado de valores a mostrar en la lista (list.component.ts)

<mat-selection-list #listFrameworks>

 <mat-list-option *ngFor="let item of frameworks">

 {{item}}

 </mat-list-option>

</mat-selection-list>

Código HTML de la lista con selección (list.component.html)

Código HTML de la lista con selección

Visualización de la lista con selección (Página Lista)

Para finalizar la página Lista, se añade un componente Angular Material de tabla, para mostrar una tabla básica con filas y columnas, para ver su utilidad y su facilidad de creación.

Como siempre, lo primero, se importa el módulo en el componente principal (app.module.ts) para tenerlo disponible en el proyecto. El módulo se llama: MatTableModule.

Acto seguido, se comienza con el desarrollo en la página Lista.

languages: Language[] = [
    {name: "Javascript", created: 1995},
    {name: "PHP", created: 1994},
    {name: "Java", created: 1995},
{name: "Python", created: 1991},
    {name: "Dart", created: 2011},
    {name: "C#", created: 2000},
  ];

  dataTitle: string[] = ["name", "created"];

Definición de datasets de la tabla (datos y campos a visualizar) (list.component.ts)

<table mat-table [dataSource]="languages" class="mat-elevation-z8">

 <!-- Name Column -->

 <ng-container matColumnDef="name">

 <th mat-header-cell *matHeaderCellDef> Name </th>

 <td mat-cell *matCellDef="let element"> {{element.name}} </td>

 </ng-container>

  

 <!-- Weight Column -->

 <ng-container matColumnDef="created">

 <th mat-header-cell *matHeaderCellDef> Creation </th>

 <td mat-cell *matCellDef="let element"> {{element.created}} </td>

 </ng-container>

 

 <tr mat-header-row *matHeaderRowDef="dataTitle"></tr>

 <tr mat-row *matRowDef="let row; columns: dataTitle;"></tr>

</table>

Definición de datasets de la tabla (datos y campos a visualizar) (list.component.html)

Por último, es necesario dar unos estilos básicos a la tabla para hacerla más grande, ya que por defecto solo coge la mínima anchura para mostrar los datos:

table {
    width: 100%;
}

Estilos básicos de la tabla (list.component.html)

Visualización de la tabla

Visualización de la tabla (Página Lista)

Formulario

Esta página se crea para mostrar algunos ejemplos de campos de formulario. La librería proporciona una gran guía de elementos de un formulario tales como: inputs, selects, datepickers, campo de autocompletado, etc. Cada uno de ellos con distintas opciones de personalización.

Siguiendo los mismos pasos que siempre, se dan de alta en componente principal (app.module.ts) los módulos de aquellos componentes de Angular Material que se necesiten.

MatInputModule,
MatRadioModule,
MatSelectModule

Módulos importados correspondiente a campos de formulario (imports – app.module.ts)

<mat-form-field class="full-width">

 <mat-label>Email</mat-label>

 <input matInput [formControl]="emailFormControl"

 placeholder="ejemplo@ejemplo.com">

</mat-form-field>

<mat-radio-group

 aria-labelledby="radio-group-label"

 class="radio-group"

 [(ngModel)]="favoriteCountry">

 <mat-radio-button class="radio-button" *ngFor="let item of countries" [value]="item">

 {{item}}

 </mat-radio-button>

</mat-radio-group>

<mat-form-field>

 <mat-select>

 <mat-option *ngFor="let item of musicGenres" [value]="item.id">

 {{item.name}}

 </mat-option>

 </mat-select>

</mat-form-field>

Estructura HTML de los componentes de formulario (form.component.html)

 favoriteCountry: string;
  countries: string[] = ['España', 'Italia', 'Francia', 'Portugal'];
  musicGenres: MusicGenre[] = [
    {id: 1, name: 'Rock'},
    {id: 2, name: 'Pop'},
    {id: 3, name: 'Metal'},
    {id: 4, name: 'Techno'}
  ];

Estructura HTML de los componentes de formulario (form.component.html)

.radio-group {
    display: flex;
    flex-direction: column;
    margin: 15px 0;
}

Estilos necesarios para los botones de radio (form.component.scss)

Vista de la página Formulario

Vista de la página Formulario

Mejorando visualmente el contenido (extra)

Al ver la imagen anterior, se aprecia que el contenido interior está muy pegado al menú lateral y a la cabecera. Esto se soluciona fácilmente estableciendo un contenedor único para el contenido y aplicando la propiedad de padding.

<div class="container-page">

 <router-outlet></router-outlet>

</div>

Englobar router-outlet con un contenedor para poder dar estilos al contenido (app.component.html)

Dentro de la propiedad -mat-sidenav-content con SASS, se establece la propiedad de relleno (padding):

.container-page{
    padding: 15px;
}

Estilos para el relleno interior del contenido (app.component.scss)

Por último, como mejora final, se establecen títulos en las páginas restantes, Lista y Formulario, dando a cada página un contenido más elegante y quedando cada una de ellas preparada para la inserción de más componentes visuales.

<h2>Lista</h2>

Título de la página Lista (list.component.html)

<h2>Formulario</h2>

Título de la página Formulario (form.component.html)

Ahora, un ejemplo de cómo quedaría la página Lista:

Ejemplo de cómo quedaría la página Lista

Conclusiones

En conclusión, hay detalles mejorables, como por ejemplo, aumentar el tamaño del menú, mostrar/ocultar menú al ocultar, etc., pero todas estas mejoras escapan al objetivo principal del artículo: crear un tema básico con Angular Material, que permite ver qué pasos seguir para añadir componentes y seguir la documentación de la librería.

Realizar una web con Angular utilizando la librería Angular Material para ayudar en la realización de componentes visuales, siguiendo la documentación y aplicando correctamente estilos CSS a los elementos es muy rápido y efectivo.

Prácticamente, todo se ha construido con componentes de Angular Material, por lo que la librería proporciona ejemplos para todo tipo de desarrollos y es muy flexible para trabajar con estilos propios. La conclusión es que es una librería muy completa para realizar aplicaciones con diseño basado en los patrones de diseño de Android, que es sencilla y rápida de utilizar. Si estás buscando programadores Angular puedes ponerte en contacto y te ayudaremos en lo que necesites.

El repositorio de código asociado se encuentra aquí: enlace.

Manuel García

Desarrollador full stack web y móvil. En evolución constante.