O que é o Angular Router no Ionic
No Ionic com Angular, a navegação entre telas é feita pelo Angular Router. Em vez de “abrir páginas” manualmente, você define um conjunto de rotas (URLs internas do app) e o Router decide qual componente deve ser exibido no ion-router-outlet. Isso traz benefícios como: navegação previsível, suporte a parâmetros na URL, guards (proteção de rotas) e organização por funcionalidades (features).
Conceitos essenciais
- Rota: mapeia um caminho (ex.:
/produtos) para um componente ou módulo. - Parâmetro de rota: parte variável do caminho (ex.:
/produtos/42onde42é oid). - Query params: parâmetros após
?(ex.:/produtos?categoria=livros). - Link declarativo: navegação via template com
[routerLink]. - Navegação programática: navegação via TypeScript com
Router. - Guard: classe que decide se uma rota pode ser acessada (ex.: exigir login).
Passo a passo: criando rotas e navegando por links
Suponha que você tenha duas telas: HomePage e ProductsPage, e uma tela de detalhe ProductDetailPage.
1) Definindo rotas no App Routing
No arquivo app-routing.module.ts, defina rotas principais e use loadChildren para carregar módulos de páginas/feature (lazy loading), mantendo o app leve.
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{
path: 'home',
loadChildren: () => import('./pages/home/home.module').then(m => m.HomePageModule)
},
{
path: 'products',
loadChildren: () => import('./features/products/products.module').then(m => m.ProductsModule)
},
// fallback opcional
{ path: '**', redirectTo: 'home' }
];
@NgModule({
imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })],
exports: [RouterModule]
})
export class AppRoutingModule {}Note que products aponta para um módulo de feature (features/products), o que facilita manutenção e crescimento do app.
2) Rotas dentro de uma feature (organização por funcionalidade)
Crie um módulo de rotas específico para a feature, por exemplo: features/products/products-routing.module.ts. Esse arquivo concentra as rotas relacionadas a produtos.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProductsPage } from './pages/products/products.page';
import { ProductDetailPage } from './pages/product-detail/product-detail.page';
const routes: Routes = [
{ path: '', component: ProductsPage },
{ path: ':id', component: ProductDetailPage }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ProductsRoutingModule {}Com isso, você obtém:
/products→ lista/products/123→ detalhe do produto 123
3) Navegação com routerLink (template)
Em uma lista de produtos, você pode criar links para o detalhe usando [routerLink]. Exemplo em products.page.html:
<ion-list>
<ion-item
*ngFor="let p of products"
[routerLink]="['/products', p.id]"
>
<ion-label>
<h2>{{ p.name }}</h2>
<p>R$ {{ p.price }}</p>
</ion-label>
</ion-item>
</ion-list>Boas práticas:
- Prefira
[routerLink]para links simples (mais declarativo e fácil de manter). - Use array de segmentos (
['/products', id]) para evitar erros de concatenação.
4) Navegação programática (TypeScript)
Quando você precisa navegar após uma ação (ex.: salvar formulário), use o Router.
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-products',
templateUrl: './products.page.html'
})
export class ProductsPage {
constructor(private router: Router) {}
goToDetail(id: string) {
this.router.navigate(['/products', id]);
}
}Rotas com parâmetros e query params
Parâmetros de rota: lendo o :id no TypeScript
Na rota /products/:id, o :id é um parâmetro. Para ler esse valor no componente de detalhe, use ActivatedRoute.
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.page.html'
})
export class ProductDetailPage implements OnInit, OnDestroy {
productId!: string;
private sub?: Subscription;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
// Recomendado quando a mesma página pode ser reutilizada com outro id
this.sub = this.route.paramMap.subscribe(params => {
this.productId = params.get('id') ?? '';
// aqui você buscaria os dados do produto com esse id
});
}
ngOnDestroy() {
this.sub?.unsubscribe();
}
}Alternativa quando você sabe que o valor não mudará durante a vida do componente (menos flexível):
this.productId = this.route.snapshot.paramMap.get('id') ?? '';Query params: filtragem e estado na URL
Query params são úteis para filtros, ordenação e paginação. Exemplo: /products?category=books&sort=price.
1) Criando um link com query params
<ion-button
[routerLink]="['/products']"
[queryParams]="{ category: 'books', sort: 'price' }"
>
Ver livros por preço
</ion-button>2) Lendo query params no TypeScript
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-products',
templateUrl: './products.page.html'
})
export class ProductsPage implements OnInit, OnDestroy {
category?: string;
sort?: string;
private sub?: Subscription;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.sub = this.route.queryParamMap.subscribe(q => {
this.category = q.get('category') ?? undefined;
this.sort = q.get('sort') ?? undefined;
// aplique filtros/ordenação na lista
});
}
ngOnDestroy() {
this.sub?.unsubscribe();
}
}3) Atualizando query params sem perder os existentes
Um padrão comum é alterar apenas um parâmetro e manter os demais. Use queryParamsHandling: 'merge'.
import { Router } from '@angular/router';
constructor(private router: Router) {}
setSort(sort: string) {
this.router.navigate([], {
queryParams: { sort },
queryParamsHandling: 'merge'
});
}Guards básicos: protegendo telas (exigir login)
Guards permitem bloquear (ou redirecionar) o acesso a rotas com base em regras. Um caso típico é exigir que o usuário esteja autenticado para acessar páginas como perfil, pedidos, checkout etc.
Estratégia simples e funcional
- Um AuthService expõe o estado de login.
- Um AuthGuard verifica esse estado.
- Rotas protegidas usam
canActivate. - Se não estiver logado, o guard redireciona para
/logine pode guardar a URL de retorno.
1) Criando um AuthService (exemplo mínimo)
Exemplo didático com estado em memória. Em apps reais, você pode integrar com token, storage seguro etc., mas o padrão de consumo via guard é o mesmo.
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class AuthService {
private loggedIn$ = new BehaviorSubject<boolean>(false);
isLoggedIn() {
return this.loggedIn$.value;
}
login() {
this.loggedIn$.next(true);
}
logout() {
this.loggedIn$.next(false);
}
}2) Criando o guard (canActivate)
O guard pode retornar boolean (permite/bloqueia) ou um UrlTree (redireciona). Retornar UrlTree é uma boa prática porque evita navegação “quebrada”.
import { Injectable } from '@angular/core';
import { CanActivate, Router, UrlTree, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '../services/auth.service';
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree {
if (this.auth.isLoggedIn()) {
return true;
}
// Redireciona para /login e guarda a URL original para voltar depois
return this.router.createUrlTree(['/login'], {
queryParams: { returnUrl: state.url }
});
}
}3) Protegendo uma rota com canActivate
Exemplo: proteger a rota /account.
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './guards/auth.guard';
const routes: Routes = [
{
path: 'account',
canActivate: [AuthGuard],
loadChildren: () => import('./pages/account/account.module').then(m => m.AccountPageModule)
},
{
path: 'login',
loadChildren: () => import('./pages/login/login.module').then(m => m.LoginPageModule)
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SomeRoutingModule {}Observação: você pode colocar essas rotas no app-routing.module.ts ou em um módulo de rotas específico, dependendo da organização do projeto.
4) Implementando o retorno após login (returnUrl)
Na página de login, leia o returnUrl (query param) e navegue para ele após autenticar.
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../../services/auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.page.html'
})
export class LoginPage implements OnInit {
returnUrl = '/home';
constructor(
private route: ActivatedRoute,
private router: Router,
private auth: AuthService
) {}
ngOnInit() {
this.returnUrl = this.route.snapshot.queryParamMap.get('returnUrl') ?? '/home';
}
doLogin() {
this.auth.login();
this.router.navigateByUrl(this.returnUrl);
}
}Exemplo de botão no template:
<ion-button expand="block" (click)="doLogin()">Entrar</ion-button>Boas práticas para rotas e guards (manutenção)
Organize por features
- Crie pastas como
features/products,features/accountcom seus própriosrouting.module.ts. - Mantenha o
app-routing.module.tscom rotas de alto nível e redirecionamentos.
Padronize nomes e caminhos
- Use nomes consistentes:
products,products/:id,account. - Evite caminhos duplicados ou muito profundos sem necessidade.
Centralize constantes de rotas (opcional)
Para reduzir strings espalhadas, você pode criar um arquivo com caminhos.
export const AppRoutes = {
home: '/home',
products: '/products',
login: '/login',
account: '/account'
} as const;Use UrlTree para redirecionar em guards
- Prefira
return this.router.createUrlTree(...)em vez de chamarnavigate()dentro do guard. - Isso mantém o fluxo de navegação mais previsível e testável.
Evite lógica de autenticação dentro do guard
- O guard deve apenas consultar um serviço (ex.:
AuthService) e decidir. - Regras de login/token/expiração ficam no serviço.
Tabela rápida: quando usar cada tipo de parâmetro
| Necessidade | Melhor opção | Exemplo |
|---|---|---|
| Identificar recurso (obrigatório) | Parâmetro de rota | /products/42 |
| Filtro/ordenação (opcional) | Query params | /products?sort=price |
| Estado compartilhável por link | Query params | /products?category=books |
| Estrutura hierárquica | Rotas aninhadas/feature routing | /account/settings |