Menú flotante con IONIC 5 + Angular desde 0

La línea de comandos de IONIC 4 (CLI en adelante) es una ayuda casi indispensable para todo desarrollador de esta plataforma. Dentro de las múltiples posibilidades que ofrece, podemos crear un «esqueleto» de aplicación completamente válida y funcional para, a partir de ella, poder desarrollar nuestra aplicación completa.

No vamos a cubrir el proceso de instalación de IONIC, Angular o las dependencias necesarias. Para eso hay muchos blogs especializados o la documentación original, donde tendrás los comandos necesarios para instalar node.js y toda la estructura necesaria en tu equipo. No es el objeto de esta entrada.

IONIC nos permite crear 3 tipos de «plantillas principales» (por entendernos…): un menú lateral, pestañas o una aplicación en blanco.

Para nuestro tutorial, podríamos elegir la plantilla del menú lateral, pues es casi lo que buscamos, pero prefiero hacerlo desde 0 para poder aplicar otros conceptos interesantes de IONIC, como inyección de dependencias, tipos Observables, etc…

Pues manos a la obra. Nos vamos al directorio donde queremos guardar nuestra súper aplicación y ejecutamos:

ionic start myApp blank

Nos pedirá el framework que queremos usar. Desde la versión 4 IONIC puede trabajar con diferentes frameworks, como VUE o React, dejando a un lado la «obligación» de usar Angular. Pero en nuestro caso, elegiremos Angular presionado la tecla «Enter».

De esta forma, esperando un poco a que se cree toda la estructura necesaria, tendríamos nuestra aplicación lista para cacharear con ella. Si cambiamos «blank» por «tabs» o «sidemenu» tendríamos los diferentes tipos de plantilla de los que hemos hablado anteriormente. También puedes cambiar «myApp» por cualquier otra cosa, y se crearía tu aplicación en ese directorio.

Ahora veremos una estructura de directorios tal que así:

Tampoco es objeto de este post explicar esta estructura. Lo único que diremos es que nuestra aplicación la montaremos en el directorio src/app. Dentro de él, me gusta tener las carpetas separadas por el tipo de archivo que va a contener, por claridad y reusabilidad.

Para nuestro proyecto, vamos a crear un componente para mostrar el menú en las páginas que necesitemos. Con el CLI los creamos:

ionic g module componentes
ionic g component componentes/menufloat --spec=false

// Como opción, podemos crear un servicio para obtener los elementos a partir de un arreglo // en algún archivo externo. Esto NO lo usaremos en nuestro proyecto
// ionic g service servicios/menu--spec=false 

Listo. Con esto, hemos creado un módulo que cargará los componentes que se encuentren en el directorio «componentes», para poder usarlos donde necesite en mi aplicación. Lo de «-spec=false» es solo para que no nos cree el archivo de pruebas.

Para que nuestro módulo de menú pueda ser usado por otros módulos externos, tengo que agregarlo en el array de «exports». Solo será necesario hacer esto para módulos usados en otras páginas, como es este el caso. Por tanto, actualizo el archivo src/app/componentes/componentes.module y lo incluyo:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MenufloatComponent } from './menufloat/menufloat.component';
import { IonicModule } from '@ionic/angular';


@NgModule({
  declarations: [
    MenufloatComponent
  ],
  exports: [
    MenufloatComponent
  ],
  imports: [
    CommonModule,
    IonicModule
  ]
})
export class ComponentesModule { }

Como último paso, debemos incluir el nuevo componente que he creado en el archivo app.module.ts, para que Angular sepa que existe y podamos usarlo. Para ello, edito mi src/app/app.module.ts y quedaría:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { ComponentesModule } from './componentes/componentes.module';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    BrowserModule, 
    IonicModule.forRoot(),
    AppRoutingModule,
    ComponentesModule
  ],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Atentos a la importación que hay que hacer:

import { ComponentesModule } from './componentes/componentes.module';

Junto con el correspondiente «imports»:

imports: [
    ...
    ComponentesModule
  ],

Y con esto ya podemos incluir nuestro módulo de menú en cualquier página de la aplicación, que es lo que vamos a hacer a continuación.

El menú lo vamos a crear a partir de un interface y un arreglo JSON que será el que me provea de todos los elementos necesarios. Para crear el interface, creamos una nueva carpeta en el raiz de nuestra aplicación. Por ejemplo, src/app/interfaces/menudata.ts con el siguiente contenido:

export interface MenuElementsInterface {
    nombre: string;
    enlace: string;
}

Ya lo tenemos todo preparado para crear el menú en sí. Nos vamos al archivo src/app/componentes/menufloat/menufloat.component.ts y tenemos que crear el arreglo de elementos del menú, tomando como base el interface que hemos creado anteriormente:

import { Component, OnInit } from '@angular/core';
import { MenuElementsInterface } from 'src/app/interfaces/menudata';

@Component({
  selector: 'app-menufloat',
  templateUrl: './menufloat.component.html',
  styleUrls: ['./menufloat.component.scss'],
})
export class MenufloatComponent implements OnInit {

  datosMenu: MenuElementsInterface[] = [
    {
      nombre: 'Opción 1',
      enlace: '/opcion1'
    },
    {
      nombre: 'Opción 2',
      enlace: '/opcion2'
    },
    {
      nombre: 'Opción 3',
      enlace: '/opcion3'
    }
  ];

  constructor() { }

  ngOnInit() {}

}

Y en el archivo src/app/componentes/menufloat/menufloat.component.html tenemos que crear el código de nuestro menú propiamente dicho:

<ion-header>
    <ion-toolbar color="primary">
      <ion-buttons slot="start">
        <ion-menu-button></ion-menu-button>
      </ion-buttons>

      <ion-title>Menú principal</ion-title>
    </ion-toolbar>
</ion-header>
  
<ion-menu side="start" menuId="menuPrincipal" contentId="menuFloat">
  <ion-content>
    <ion-list>
      <ion-menu-toggle *ngFor="let c of datosMenu">
        <ion-item routerLink="[c.enlace]">
          <ion-label>{{ c.nombre }}</ion-label>
        </ion-item>
      </ion-menu-toggle>
    </ion-list>
  </ion-content>
</ion-menu>

Para terminar, podemos usar este menú en cualquier página. Por ejemplo, para hacerlo en la página de inicio por defecto que nos proporciona IONIC debemos modificar el archivo src/app/home/home.module.ts para importar el componente «Componentes», valga la redundancia:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';

import { HomePage } from './home.page';
import { ComponentesModule } from '../componentes/componentes.module';

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    RouterModule.forChild([
      {
        path: '',
        component: HomePage
      }
    ]),
    ComponentesModule
  ],
  declarations: [HomePage]
})
export class HomePageModule {}

Ya podemos usarlo en src/app/home/home.page.html:

<app-menufloat></app-menufloat>

<ion-content>
  <div class="ion-padding">
    The world is your oyster.
    <p>If you get lost, the <a target="_blank" rel="noopener" href="https://ionicframework.com/docs/">docs</a> will be your guide.</p>
  </div>
</ion-content>

Por último, para decirle a Angular que nuestro menú es el que tiene como ID «menuFloat» tenemos que hacer un pequeño cambio en src/app/app.component.html:

<ion-app>
  <ion-router-outlet id="menuFloat"></ion-router-outlet>
</ion-app>

Ya con esto tendríamos un menú tal que así:

Este código tiene MUCHÍSIMAS mejoras y cambios. Es solo para dar una idea del uso de componentes, inyección de dependencias y demás.

Espero que os haya gustado y ¡¡nos vemos en el siguiente reto!!