# Aula 4.5 - Rotas, layouts e navegação

## 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`](../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:

```text
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.

```ts
{ 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.

```text
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:

```html
<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.

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

### `routerLink` é igual a `href`?

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

```html
<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

```text
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

```ts
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:

```ts
{ 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

```ts
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

```ts
@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

```html
<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

```html
<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.

## 8. Link ativo

```html
<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:

```html
<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

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

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

## 11. Criando link com parâmetro

```html
<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:

```ts
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:

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

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

```ts
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`

```ts
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

```text
/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

```ts
{ 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

```ts
{ 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.

```ts
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

```ts
{ 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

```ts
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

```ts
{
  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.

## 23. Botões e links têm papéis diferentes

```text
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:

```html
<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.

```text
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](../exemplos/aula-4.5/index.html).

### 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.

### Exercício 4 — Link ativo

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

- [Visão geral do Angular Router](https://angular.dev/guide/routing)
- [Definição de rotas](https://angular.dev/guide/routing/define-routes)
- [Navegação para rotas](https://angular.dev/guide/routing/navigate-to-routes)
- [Leitura do estado da rota](https://angular.dev/guide/routing/read-route-state)
- [Redirects](https://angular.dev/guide/routing/redirecting-routes)
- [Tarefas comuns do Router](https://angular.dev/guide/routing/common-router-tasks)
