Rutes a Angular¶
Angular s'utilitza habitualment per desenvolupar Single Page Applications (SPA). Tot i ser una SPA, l'aplicació ha de comportar-se de manera similar als llocs web tradicionals pel que fa a les URLs (Uniform Resource Identifiers). Això implica que necessitem poder referenciar externament les diferents parts de l'aplicació, tenir la capacitat de navegar enrere i endavant a l'historial del navegador i gestionar rutes virtuals adequadament.
Les rutes a Angular es defineixen al fitxer app-routing.module.ts. Les rutes són objectes que contenen el camí (path) i el component al qual fan referència. Les pàgines en una SPA d'Angular estan representades per components, i el router carrega les rutes dins d'un <router-outlet> a la plantilla principal de l'aplicació.
Exemple Bàsic de Rutes¶
El següent és un exemple de com configurar rutes bàsiques a Angular:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { PlanetListComponent } from './planets/planet-list/planet-list.component';
import { SunComponent } from './sun/sun.component';
import { PlanetDetailComponent } from './planets/planet-detail/planet-detail.component';
import { PlanetEditComponent } from './planets/planet-edit/planet-edit.component';
import { LoginComponent } from './auth/login/login.component';
import { AuthGuard } from './auth/auth.guard';
import { PlanetResolveService } from './planets/planet-resolve.service';
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'planets', canActivate: [AuthGuard], component: PlanetListComponent },
{ path: 'suns', canActivate: [AuthGuard], component: SunComponent },
{ path: 'planet/:id', canActivate: [AuthGuard], component: PlanetDetailComponent },
{ path: 'planet/edit/:id', canActivate: [AuthGuard], resolve: { planet: PlanetResolveService }, component: PlanetEditComponent },
{ path: 'login', component: LoginComponent },
{ path: '**', pathMatch: 'full', redirectTo: 'home' }
];
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
path: Defineix l'URI per la ruta.component: El component que es carrega quan es navega a aquesta ruta.canActivate: Defineix guardes que protegeixen les rutes.resolve: Permet precarregar dades abans que el component es carregui.
Rutes amb Hash¶
Una manera d'implementar SPA sense manipular el servidor és emprar una almohadilla (#) al principi de la ruta:
http://localhost:4200/#/home
Això és més antic, però funciona a tots els navegadors, simplifica l'enviament de paràmetres i evita la manipulació del servidor. Perquè funcioni, cal afegir withHashLocation() als providers del bootstrap:
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes, withHashLocation()),
],
});
Creació de Rutes¶
- Ruta Bàsica: Defineix un camí i el component que s'activa.
{ path: 'home', component: HomeComponent }
- Ruta amb Guard: Protegeix rutes usant guardes.
{ path: 'planets', canActivate: [AuthGuard], component: PlanetListComponent }
- Ruta amb Paràmetres: Permet passar paràmetres a la URL.
{ path: 'planet/:id', canActivate: [AuthGuard], component: PlanetDetailComponent }
- Ruta amb Resolve: Precarrega dades necessàries pel component.
{ path: 'planet/edit/:id', canActivate: [AuthGuard], resolve: { planet: PlanetResolveService }, component: PlanetEditComponent }
- Ruta per Defecte: Redirigeix a una ruta específica si la ruta no existeix.
{ path: '**', pathMatch: 'full', redirectTo: 'home' }
Enllaços de Navegació¶
Per crear enllaços de navegació a Angular, s'utilitza [routerLink] en lloc de href:
<a class="nav-link active" aria-current="page" [routerLink]="['home']">Home</a>
Si la ruta té més nivells, s'utilitzen elements addicionals a l'array.
<a class="nav-link" aria-current="page" [routerLink]="['home']" [routerLinkActive]="['active']">Home</a>
L'atribut routerLinkActive pot estar sense claudàtors i aplicar-se a l'element pare de l'enllaç si cal.
Navegació per Codi¶
Per navegar per codi a Angular, s'importa el Router i s'injecta al constructor:
import { Router } from '@angular/router';
constructor(private router: Router) {}
detailsProduct(id: number): void {
this.router.navigate(['/product', id]);
}
Obtenir Paràmetres de les Rutes¶
Les rutes poden contenir paràmetres, com un id. Per obtenir aquests paràmetres, s'utilitza ActivatedRoute:
import { ActivatedRoute } from '@angular/router';
constructor(private activatedRoute: ActivatedRoute) { }
ngOnInit(): void {
this.activatedRoute.params.subscribe(params => {
console.log(params);
});
}
Els paràmetres (params) són un observable al qual ens hi subscrivim per rebre els valors passats a la URL.
A partir d'Angular 16, es poden configurar els paràmetres del router per acceptar-los mitjançant @Input() utilitzant withComponentInputBinding().
bootstrapApplication(App, {
providers: [
provideRouter(routes,
//... other features
withComponentInputBinding() // <-- enable this feature
)
],
});
@Input() query?: string; // Normal
@Input('q') queryParam?: string; // Renombrar el paràmetre
Al router:
{ path: 'planet/:query', canActivate: [AuthGuard], component: PlanetDetailComponent }
Transicions a Angular (2024)¶
Les transicions a Angular permeten crear animacions suaus entre diferents estats de l'aplicació. Actualment, la funcionalitat completa d'aquestes transicions només està totalment disponible a Google Chrome. A continuació es detalla com implementar i personalitzar les transicions a Angular.
Definició d'Animacions en CSS¶
Primer, definim les animacions CSS utilitzant @keyframes. Això permet fer rotacions dels elements durant les transicions.
@keyframes rotate-out {
to {
transform: rotate(90deg);
}
}
@keyframes rotate-in {
from {
transform: rotate(-90deg);
}
}
::view-transition-old(count),
::view-transition-new(count) {
animation-duration: 200ms;
animation-name: -ua-view-transition-fade-in, rotate-in;
}
::view-transition-old(count) {
animation-name: -ua-view-transition-fade-out, rotate-out;
}
En aquest exemple:
- rotate-out: fa girar un element 90 graus.
- rotate-in: fa girar un element des de -90 graus fins a la seva posició original.
- ::view-transition-old(count) i ::view-transition-new(count): apliquen les animacions durant la transició.
Configuració de Rutes a Angular¶
Per habilitar les transicions, configurem les rutes a app-routing.module.ts utilitzant provideRouter i afegint withViewTransitions().
providers: [
provideRouter(
[
{ path: '', pathMatch: 'full', redirectTo: '/0' },
{ path: ':count', component: Counter },
],
withViewTransitions(),
withComponentInputBinding()
),
],
provideRouter: Defineix les rutes de l'aplicació.withViewTransitions(): Habilita les transicions de vista.withComponentInputBinding(): Permet l'enllaç d'entrada del component.
Personalització de les Transicions¶
És possible personalitzar les transicions al fitxer CSS.
::view-transition-old(count),
::view-transition-new(count) {
animation-duration: 200ms;
animation-name: -ua-view-transition-fade-in, rotate-in;
}
::view-transition-old(count) {
animation-name: -ua-view-transition-fade-out, rotate-out;
}
Aquí es defineixen les durades i els noms de les animacions per a les transicions d'entrada i sortida.
Ús de onViewTransitionCreated¶
withViewTransitions accepta un objecte amb la funció onViewTransitionCreated per gestionar esdeveniments de transició.
withViewTransitions({
onViewTransitionCreated: ({ transition }) => {
const router = inject(Router);
const targetUrl = router.getCurrentNavigation()!.finalUrl!;
const config = {
paths: 'exact',
matrixParams: 'exact',
fragment: 'ignored',
queryParams: 'ignored',
};
if (router.isActive(targetUrl, config)) {
transition.skipTransition();
}
},
})
En aquest exemple:
-
onViewTransitionCreated: s'invoca quan es crea una transició de vista. -
transition.skipTransition(): cancel·la l'animació si només canvien el fragment o els paràmetres de consulta.