Engenharia de IA Aplicada à Programação Web
Aula 5 de 10
Navegar por módulos e aulas
  1. 01 Fundamentos da Web
  2. 02 JavaScript moderno
  3. 03 TypeScript, Git e qualidade
  4. 04 Angular
  5. 05 Node.js, NestJS e APIs
  1. 4.1 Introdução ao Angular e componentes
  2. 4.2 Templates, bindings e control flow
  3. 4.3 Composição, inputs e outputs
  4. 4.4 Serviços e injeção de dependência
  5. 4.5 Rotas, layouts e navegação
  6. 4.6 Formulários e validação
  7. 4.7 HTTP, APIs e RxJS
  8. 4.8 Signals e estado da interface
  9. 4.9 Interceptors, erros e acessibilidade
  10. 4.10 Testes, compilação e projeto final

Módulo 4 · Aula 4.5

Rotas, layouts e navegação

2 horas Teoria + laboratório Angular
Ver fonte Markdown

Identificação

  • Duração: 2 horas
  • Tipo: teoria aplicada e laboratório
  • Entrega: aplicação Angular com múltiplas páginas
  • Laboratório: ../exemplos/aula-4.5/index.html

Introdução

O que é uma URL?

URL é o endereço de um recurso na Web. Ela pode conter protocolo, domínio, caminho, parâmetros de consulta e fragmento:

https://knowledge.ai/tasks/42?tab=history#comments
└─ protocolo  └ domínio └ caminho └ query    └ fragmento

Nesta aula, o caminho será a parte principal. /tasks representa a lista e /tasks/42 representa o detalhe da tarefa 42.

O que é uma rota?

Rota é uma regra que associa um padrão de URL ao componente que deve aparecer.

{ path: "tasks", component: TaskListPage }

Quando o caminho ativo é /tasks, o Router mostra TaskListPage no local definido pela aplicação.

Rota é igual a página HTML?

Não necessariamente. Em uma aplicação Angular, várias rotas podem usar o mesmo index.html. O Router troca componentes dentro da página carregada. Ainda assim, cada rota deve se comportar como uma página: possuir URL, título, conteúdo principal e navegação compreensível.

O que é uma SPA?

SPA significa single-page application, ou aplicação de página única. O navegador carrega a base da aplicação e o roteador do cliente atualiza partes da interface sem substituir todo o documento a cada clique interno.

navegação tradicional: link → servidor → novo documento HTML
navegação Angular:     Router → nova URL → troca no outlet

Isso não significa que a aplicação só tenha uma tela. Ela pode ter muitas páginas lógicas, cada uma com sua URL.

O que é o Angular Router?

É a biblioteca oficial @angular/router que coordena URLs, componentes, links e estado de navegação. Projetos criados pelo Angular CLI normalmente já incluem o pacote.

O que é RouterOutlet?

É o espaço reservado onde o componente da rota ativa será renderizado:

<main>
  <router-outlet />
</main>

O cabeçalho e a navegação ao redor permanecem. Apenas o conteúdo do outlet muda.

O que é um layout?

Layout é a estrutura persistente que organiza páginas: cabeçalho, menu, área principal e rodapé. Nesta aula, o componente raiz será o shell da Knowledge AI.

App shell
├── cabeçalho
├── navegação
└── RouterOutlet
    └── página da rota ativa

Ambos criam navegação em links, mas RouterLink pede ao Angular para navegar sem recarregar todo o documento:

<a routerLink="/tasks">Tarefas</a>

Use links reais, não div com clique. Para sites externos, downloads ou recursos que não pertencem ao Router, href continua correto.

Atualizar a página quebra uma SPA?

Pode quebrar se o servidor não estiver configurado. Ao abrir diretamente /tasks/42, o servidor precisa entregar o index.html da aplicação para que o Router interprete o caminho. Em produção, configuramos um fallback de rotas. Isso é diferente da rota coringa dentro do Angular.

Como isso entra na Knowledge AI?

Criaremos um shell persistente e quatro resultados de navegação:

  • dashboard em /dashboard;
  • lista em /tasks;
  • detalhe em /tasks/:id;
  • página não encontrada para caminhos desconhecidos.

Objetivos

Ao final da aula, o aluno deverá conseguir:

  1. identificar partes básicas de uma URL;
  2. explicar rota, Router, SPA, outlet e layout;
  3. declarar um array Routes;
  4. registrar o Router com provideRouter;
  5. importar e usar RouterOutlet;
  6. navegar com RouterLink;
  7. indicar o link ativo de forma acessível;
  8. criar rotas com parâmetros;
  9. ler parâmetros com input binding ou ActivatedRoute;
  10. criar redirect inicial e rota coringa;
  11. explicar a ordem first match wins;
  12. diferenciar fallback do servidor e 404 do Angular.

Pré-requisitos

  • Aulas 4.1 a 4.4 concluídas;
  • componentes standalone e templates;
  • inputs, serviços e injeção de dependência;
  • noções de URL e requisições da Aula 1.1;
  • HTML semântico e navegação por links.

Pergunta orientadora

Como transformar componentes isolados em páginas acessíveis por URLs previsíveis?

Roteiro sugerido

Etapa Duração
URL, rota e SPA 20 min
Configuração e outlet 25 min
Links, layout e acessibilidade 25 min
Parâmetros, redirects e 404 30 min
Laboratório 15 min
Revisão 5 min

1. Três peças essenciais

Routes       → relacionam URL e componente
RouterOutlet → recebe o componente ativo
RouterLink   → inicia navegação interna

Sem rotas, o Router não sabe o que mostrar. Sem outlet, não há destino visual. Sem links, a URL ainda pode ser digitada, mas a interface não oferece navegação.

2. Arquivo de rotas

import { Routes } from "@angular/router";

export const routes: Routes = [
  { path: "dashboard", component: DashboardPage },
  { path: "tasks", component: TaskListPage },
];

Projetos atuais costumam manter essa configuração em app.routes.ts.

3. Caminhos não começam com barra

Na configuração:

{ path: "tasks", component: TaskListPage }

No navegador, o resultado será /tasks. O Router compõe os segmentos; não coloque / no início de path.

4. Registrando o Router

import { ApplicationConfig } from "@angular/core";
import { provideRouter } from "@angular/router";
import { routes } from "./app.routes";

export const appConfig: ApplicationConfig = {
  providers: [provideRouter(routes)],
};

provideRouter registra os serviços necessários no ambiente da aplicação.

5. Componente raiz como shell

@Component({
  selector: "app-root",
  imports: [RouterLink, RouterLinkActive, RouterOutlet],
  templateUrl: "./app.html",
  styleUrl: "./app.css",
})
export class App {}

O shell importa as diretivas que usa. As páginas roteadas não precisam ser inseridas manualmente no template raiz.

6. Criando o layout

<header>
  <a routerLink="/dashboard">Knowledge AI</a>
  <nav aria-label="Navegação principal">
    <a routerLink="/dashboard">Dashboard</a>
    <a routerLink="/tasks">Tarefas</a>
  </nav>
</header>

<main id="main-content">
  <router-outlet />
</main>

O header permanece enquanto o outlet troca a página.

7. Navegação declarativa

<a routerLink="/tasks">Ver tarefas</a>

Use RouterLink quando o destino faz parte da aplicação. Links preservam recursos do navegador, como abrir em nova guia e copiar endereço.

<a
  routerLink="/tasks"
  routerLinkActive="is-active"
  ariaCurrentWhenActive="page"
>
  Tarefas
</a>

RouterLinkActive aplica a classe. ariaCurrentWhenActive="page" comunica a página atual a tecnologias assistivas.

9. Correspondência exata

Um link para /tasks também pode ser considerado ativo em /tasks/42. Quando isso não for desejado, configure opções de correspondência:

<a
  routerLink="/tasks"
  routerLinkActive="is-active"
  [routerLinkActiveOptions]="{ exact: true }"
>

Decida se o item representa uma seção ou uma página específica.

10. Rotas com parâmetro

{ path: "tasks/:id", component: TaskDetailPage }

O segmento :id é variável. /tasks/7 e /tasks/42 usam o mesmo componente com valores diferentes.

<a [routerLink]="['/tasks', task.id]">
  {{ task.title }}
</a>

O array evita concatenar manualmente segmentos e deixa a intenção clara.

12. Parâmetro não é automaticamente número

Valores da URL chegam como texto. Mesmo /tasks/42 fornece "42". Valide e converta antes de procurar a tarefa:

const taskId = Number(id);

if (!Number.isInteger(taskId) || taskId <= 0) {
  // representar identificador inválido
}

Nunca confie na URL apenas porque foi criada pela sua interface.

13. Binding de estado para inputs

Configuração atual:

providers: [
  provideRouter(routes, withComponentInputBinding()),
]

Com uma rota tasks/:id, o componente pode receber o parâmetro em um input com o mesmo nome:

export class TaskDetailPage {
  readonly id = input.required<string>();
}

Essa abordagem reduz código de adaptação e mantém o contrato visível.

14. Alternativa com ActivatedRoute

export class TaskDetailPage {
  private readonly route = inject(ActivatedRoute);
  readonly id = this.route.snapshot.paramMap.get("id");
}

O snapshot representa um instante e não reflete mudanças futuras. Para reagir ao mesmo componente recebendo outro parâmetro, use os observables da rota ou component input binding.

15. Parâmetro de rota e query parameter

/tasks/42        → id identifica o recurso
/tasks?status=done → status ajusta filtro opcional

Use parâmetros de rota para identidade estrutural. Use query parameters para filtros, ordenação, paginação e opções que não mudam qual recurso principal é acessado.

16. Redirect inicial

{ path: "", redirectTo: "dashboard", pathMatch: "full" }

Quando a aplicação abre na raiz, o Router redireciona para /dashboard. pathMatch: "full" é essencial no caminho vazio; sem ele, o prefixo vazio combina com todos os caminhos e pode causar redirects indevidos.

17. Página não encontrada

{ path: "**", component: NotFoundPage }

** captura qualquer caminho ainda não reconhecido. A página deve explicar o erro e oferecer um caminho seguro de volta.

18. A ordem importa

O Angular usa first match wins: a primeira rota compatível vence.

export const routes: Routes = [
  { path: "tasks/new", component: TaskCreatePage },
  { path: "tasks/:id", component: TaskDetailPage },
  { path: "tasks", component: TaskListPage },
  { path: "**", component: NotFoundPage },
];

Se tasks/:id viesse antes, a palavra new poderia ser tratada como identificador. A coringa sempre fica por último.

19. Título da página

{ path: "dashboard", component: DashboardPage, title: "Dashboard | Knowledge AI" }

O Router atualiza o título do documento. Títulos específicos ajudam orientação, histórico, favoritos e acessibilidade.

20. Navegação programática

private readonly router = inject(Router);

async save(): Promise<void> {
  await this.taskStore.save();
  await this.router.navigate(["/tasks"]);
}

Use RouterLink para destinos declarativos. Use Router.navigate quando a navegação depende do resultado de uma operação.

21. Rotas filhas e layouts aninhados

{
  path: "settings",
  component: SettingsLayout,
  children: [
    { path: "profile", component: ProfilePage },
    { path: "security", component: SecurityPage },
  ],
}

SettingsLayout precisa de seu próprio RouterOutlet. Rotas filhas permitem manter um layout específico enquanto apenas uma subárea muda.

22. Navegação e estado

Não guarde a página atual em um booleano como showDashboard. A URL deve ser a fonte de verdade da navegação. Isso preserva histórico, links compartilháveis e atualização do navegador.

link   → leva a outro endereço
botão  → executa uma ação na página atual

Use <a routerLink> para abrir detalhes. Use <button> para alternar status. Não escolha pelo estilo visual.

24. Base URL em subdiretório

Angular usa a tag <base> para resolver URLs. Na raiz do domínio:

<base href="/">

Se a compilação for publicada em /site/PosIA/app/, configure o base href para esse subdiretório na compilação. Uma base incorreta quebra assets e navegação profunda.

25. Fallback do servidor

Ao receber /tasks/42 diretamente, Apache, Nginx ou outro host deve devolver o index.html da aplicação quando não existir arquivo físico. Depois, o Angular decide qual componente renderizar.

servidor: caminho sem arquivo → index.html
Angular:  caminho conhecido → componente
Angular:  caminho desconhecido → NotFoundPage

O fallback não deve redirecionar arquivos reais nem substituir endpoints da API.

26. Segurança

Uma rota escondida no menu não está protegida. Guards melhoram o fluxo da interface, mas autorização real precisa ser validada na API NestJS. O usuário pode digitar uma URL ou modificar o JavaScript do navegador.

27. Laboratório guiado

Abra o simulador de rotas.

Etapa 1 — Navegue pelo menu

Observe o shell permanecer enquanto o conteúdo do outlet muda.

Etapa 2 — Abra uma tarefa

A lista cria /tasks/:id; o detalhe recebe o valor do parâmetro.

Etapa 3 — Teste o histórico

Use voltar e avançar do simulador para percorrer as rotas visitadas.

Etapa 4 — Digite uma rota desconhecida

A rota ** ativa a página não encontrada sem remover o layout.

Etapa 5 — Examine a fonte

Compare configuração, shell e detalhe tipado.

28. Sobre o laboratório estático

O laboratório simula um Router dentro da página para funcionar sem instalar Angular. A barra de endereço é didática e não altera o endereço real do material. A pasta src/app contém a implementação Angular equivalente.

29. Erros comuns

Colocar barra no path

Use path: "tasks", não path: "/tasks".

Usar href interno e recarregar tudo

Use RouterLink para rotas pertencentes à aplicação.

Usar botão para navegação

Links comunicam destino e preservam comportamentos do navegador.

Colocar ** antes das outras rotas

A coringa captura tudo e impede as rotas seguintes.

Esquecer pathMatch: "full" no redirect vazio

O prefixo vazio combina com qualquer URL.

Tratar o parâmetro como número sem validação

Dados da URL são externos e chegam como texto.

Não configurar o servidor

Links internos funcionam, mas atualizar uma rota profunda retorna 404 do host.

Usar rota como autorização

O back-end precisa validar acesso em cada operação protegida.

30. Boas práticas

  • dê URLs previsíveis às páginas;
  • mantenha rotas em arquivo próprio;
  • use layout semântico e um conteúdo principal;
  • prefira links para navegação;
  • indique a página ativa com aria-current;
  • defina títulos específicos;
  • ordene do mais específico ao mais genérico;
  • deixe a rota coringa por último;
  • valide parâmetros;
  • configure base href e fallback do host;
  • preserve a URL como fonte de verdade;
  • não confunda navegação com autorização.

31. Exercícios

Exercício 1 — Rotas estáticas

Crie páginas /about e /settings.

Exercício 2 — Layout

Mantenha cabeçalho e navegação fora do outlet.

Exercício 3 — Parâmetro

Crie /users/:id e converta o identificador com validação.

Adicione classe ativa e ariaCurrentWhenActive="page".

Exercício 5 — 404

Crie uma página que explique o erro e ofereça link para o dashboard.

32. Desafio

Crie uma aplicação com:

  • shell persistente;
  • dashboard, lista, criação e detalhe;
  • provideRouter;
  • RouterOutlet;
  • links acessíveis;
  • títulos por rota;
  • parâmetro :id validado;
  • query parameter de filtro;
  • redirect inicial com pathMatch: "full";
  • rota ** por último;
  • navegação programática após salvar;
  • documentação do fallback necessário no servidor.

33. Lista de verificação de conclusão

  • Explico URL, rota, Router e SPA.
  • Sei o papel de Routes, Outlet e Link.
  • Registro o Router com provideRouter.
  • Construo um shell persistente.
  • Uso links semânticos para navegar.
  • Indico a página atual de modo acessível.
  • Crio e valido parâmetro de rota.
  • Diferencio route param e query param.
  • Configuro redirect vazio corretamente.
  • Deixo a rota coringa por último.
  • Entendo base href e fallback do servidor.

34. Critérios de avaliação

Critério Pontos
Configuração de rotas 20
Layout e outlet 20
Links e acessibilidade 20
Parâmetros e validação 20
Redirect, 404 e ordem 10
Clareza e organização 10
Total 100

Resumo

Nesta aula, aprendemos que:

  • rota relaciona um padrão de URL a um componente;
  • SPA pode possuir muitas páginas lógicas;
  • provideRouter registra o roteador;
  • RouterOutlet marca onde a página ativa aparece;
  • o layout permanece ao redor do outlet;
  • RouterLink navega internamente sem recarregar o documento;
  • parâmetros identificam recursos e chegam como texto;
  • component input binding pode entregar dados da rota a inputs;
  • a primeira rota compatível vence;
  • redirect vazio exige pathMatch: "full";
  • ** representa caminhos desconhecidos;
  • o servidor precisa devolver index.html em rotas profundas.

Próxima aula

Na Aula 4.6, criaremos formulários tipados, validações e retorno acessível para cadastrar e editar tarefas.

Fontes oficiais