Routes en Angular

Intermedio
Angular
Angular
Actualizado: 27/08/2024

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

El concepto de rutas o routes se refiere a la capacidad de definir diferentes vistas o componentes correspondientes a diferentes rutas de URL en una aplicación de una sola página (SPA).

¿Te está gustando esta lección?

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Esto permite a los usuarios navegar por la aplicación cambiando la URL y ver diferentes partes de la interfaz de usuario sin recargar la página.

Conceptos clave de routes

Routes: Es una colección de objetos Route que definen cómo el router debe navegar entre diferentes vistas de la aplicación. Cada Route es un objeto que contiene propiedades clave como path, component, redirectTo, y otras configuraciones avanzadas.

Route Parameters: Las rutas pueden incluir parámetros que permiten a la aplicación ser más dinámica. Estos parámetros pueden ser opcionales o requeridos y se utilizan para pasar información a los componentes.

Nested Routes: Angular permite definir rutas anidadas, donde una ruta padre puede tener rutas hijas que se representan dentro del contexto del componente padre.

Lazy Loading: Las rutas pueden configurarse para cargar módulos de manera diferida (lazy loading), lo que mejora el rendimiento al cargar solo los módulos necesarios en lugar de toda la aplicación al inicio.

Guards: Las guardias son servicios que implementan interfaces específicas para controlar el acceso a las rutas. Existen diferentes tipos de guardias como CanActivate, CanActivateChild, CanDeactivate, Resolve, y CanLoad.

Configuración de routes

Las rutas en Angular se definen como una matriz de objetos que describen las rutas y sus componentes asociados.

A partir de Angular 17, la configuración de rutas puede hacerse sin un módulo explícito, lo que simplifica la configuración de enrutamiento en las aplicaciones.

Para configurar las rutas en Angular, primero se define un arreglo de rutas (Routes), y luego se pasa este arreglo al método RouterModule.forRoot (para configuraciones en la raíz de la aplicación) o RouterModule.forChild (para módulos secundarios).

Ejemplo de configuración de rutas:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

const routes: Routes = [
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: 'home', component: HomeComponent },
  { path: 'about', component: AboutComponent },
  { path: '**', component: PageNotFoundComponent }
];

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

En este ejemplo:

  • La ruta '' redirige a /home utilizando redirectTo y pathMatch: 'full'.
  • La ruta /home carga el componente HomeComponent.
  • La ruta /about carga el componente AboutComponent.
  • La ruta ** actúa como un comodín que captura cualquier ruta no definida, mostrando un componente de página no encontrada (PageNotFoundComponent).

Parámetros de ruta

Las rutas pueden aceptar parámetros, lo que permite a la aplicación ser más dinámica y flexible. Los parámetros pueden ser necesarios para ciertas rutas y se utilizan para pasar datos al componente correspondiente.

Ejemplo de parámetros de ruta:

const routes: Routes = [
  { path: 'article/:id', component: ArticleComponent }
];

Para acceder a los parámetros dentro del componente:

import { ActivatedRoute } from '@angular/router';

@Component({
  // ...
})
export class ArticleComponent implements OnInit {
  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.route.paramMap.subscribe(params => {
      const articleId = params.get('id');
      // Lógica para manejar el artículo basado en el ID
    });
  }
}

Rutas anidadas

Las rutas anidadas permiten que una ruta padre tenga rutas hijas que se representan dentro del contexto del componente padre. Esto es útil para organizar la navegación de manera jerárquica.

Ejemplo de rutas anidadas:

const routes: Routes = [
  {
    path: 'dashboard',
    component: DashboardComponent,
    children: [
      { path: 'profile', component: ProfileComponent },
      { path: 'settings', component: SettingsComponent }
    ]
  }
];

Carga diferida (Lazy Loading)

Angular soporta la carga diferida de módulos, lo que mejora el rendimiento de la aplicación al cargar solo los módulos necesarios en lugar de toda la aplicación al inicio.

Ejemplo de carga diferida:

const routes: Routes = [
  { path: 'feature', loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule) }
];

En este ejemplo, el módulo FeatureModule solo se cargará cuando el usuario navegue a la ruta /feature.

Guardias de ruta

Las guardias son servicios que implementan interfaces específicas y pueden ser usadas para controlar el acceso a las rutas. Las guardias más comunes son CanActivate y CanLoad.

Usando la interfaz CanActivate

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(): boolean {
    if (this.authService.isLoggedIn()) {
      return true;
    } else {
      this.router.navigate(['/login']);
      return false;
    }
  }
}

Y en la configuración de rutas:

const routes: Routes = [
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }
];

Usando una función como guard

A partir de Angular 15, se pueden usar funciones en lugar de servicios que implementen interfaces.

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(): boolean {
    if (this.authService.isLoggedIn()) {
      return true;
    } else {
      this.router.navigate(['/login']);
      return false;
    }
  }
}

Y en la configuración de rutas:

const routes: Routes = [
  { path: 'dashboard', component: DashboardComponent, canActivate: [authGuardFn] }
];

Diferencias entre la interfaz y la función

  - Interfaz CanActivate: Es más adecuada cuando se necesita encapsular lógica compleja dentro de un servicio. Es útil para reusar la lógica de guardia en diferentes rutas y cuando se requiere dependencia de inyección de dependencias (DI) en el constructor del servicio.

  - Función CanActivateFn: Es más sencilla y directa. Ideal para casos donde la lógica de la guardia es simple y no se necesita reutilizar en múltiples rutas. También es útil para evitar la creación de servicios innecesarios.

Resolver datos

Los resolvers permiten obtener datos antes de que una ruta se active, asegurando que el componente tenga todos los datos necesarios al cargar.

Usando la interfaz Resolve

import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Observable } from 'rxjs';
import { DataService } from './data.service';

@Injectable({
  providedIn: 'root'
})
export class DataResolver implements Resolve<Observable<any>> {
  constructor(private dataService: DataService) {}

  resolve() {
    return this.dataService.getData();
  }
}

Y en la configuración de rutas:

const routes: Routes = [
  { path: 'data', component: DataComponent, resolve: { data: DataResolver } }
];

Usando una función como resolver

import { inject } from '@angular/core';
import { ResolveFn } from '@angular/router';
import { DataService } from './data.service';

export const dataResolverFn: ResolveFn<Observable<any>> = (route, state) => {
  const dataService = inject(DataService);
  return dataService.getData();
};

Y en la configuración de rutas:

const routes: Routes = [
  { path: 'data', component: DataComponent, resolve: { data: dataResolverFn } }
];

Diferencias entre la interfaz y la función

  - Interfaz Resolve: Al igual que con las guardias, es adecuada para encapsular lógica compleja de resolución de datos dentro de un servicio. Es útil cuando se requiere una configuración más estructurada y reutilizable.

  - Función ResolveFn: Proporciona una manera más sencilla y directa de definir resolvers. Es ideal para casos donde la lógica es simple y no se necesita reutilización extensa.

Módulos internos y principal

En Angular, la configuración de rutas se realiza principalmente a través de dos tipos de módulos: el módulo principal y módulos específicos para diferentes partes de la aplicación.

Módulo principal

En este módulo se definen las rutas raíz de la aplicación.

Se importa el módulo RouterModule desde @angular/router y se utiliza el método estático forRoot() para proporcionar la configuración de las rutas.

Ejemplo de módulo principal:

// src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';

const routes: Routes = [
    { path: '', component: HomeComponent },
    { path: 'about', component: AboutComponent }
];

@NgModule({
    declarations: [HomeComponent, AboutComponent],
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppModule { }

En este ejemplo:

  • Se configuran dos rutas: la ruta de inicio (representada por una cadena vacía) y la ruta "about".
  • Cada ruta está asociada a un componente que se mostrará cuando se navegue a la ruta.

Módulos internos

Las partes específicas de la aplicación pueden tener sus propios módulos y rutas. En estos módulos, se importa RouterModule y se utiliza el método forChild() para definir rutas específicas.

Ejemplo de módulo interno:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProductsComponent } from './products.component';
import { ProductDetailComponent } from './product-detail.component';

const routes: Routes = [
    { path: 'products', component: ProductsComponent },
    { path: 'product/:id', component: ProductDetailComponent }
];

@NgModule({
    declarations: [ProductsComponent, ProductDetailComponent],
    imports: [RouterModule.forChild(routes)],
    exports: [RouterModule]
})
export class ProductsModule { }

Aprendizajes de esta lección

  1. Comprender el concepto de rutas (Routes) en Angular
  2. Aprender a configurar rutas en Angular.
  3. Conocer el módulo principal y módulos internos y aprender a configurarlos.
  4. Aprender a implementar la navegación entre rutas.
  5. Implementar guardias y resolvers en rutas.

Completa Angular y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración