Um guia completo para roteamento em Angular

Publicados: 2022-03-10
Resumo rápido ↬ Ao longo deste tutorial, Ahmed Bouchefra apresenta o Angular Router e como você pode usá-lo para criar aplicativos do lado do cliente e aplicativos de página única com roteamento e navegação.

Caso você ainda não esteja familiarizado com o Angular 7, gostaria de aproximá-lo de tudo que esse impressionante framework front-end tem a oferecer. Vou orientá-lo em um aplicativo de demonstração Angular que mostra diferentes conceitos relacionados ao roteador, como:

  • A tomada do roteador,
  • Rotas e caminhos,
  • Navegação.

Também mostrarei como usar o Angular CLI v7 para gerar um projeto de demonstração onde usaremos o roteador Angular para implementar roteamento e navegação. Mas primeiro, permita-me apresentá-lo ao Angular e examinar alguns dos novos recursos importantes em sua versão mais recente.

Apresentando o Angular 7

Angular é uma das estruturas de front-end mais populares para criar aplicativos da Web do lado do cliente para a Web móvel e de desktop. Ele segue uma arquitetura baseada em componentes em que cada componente é um pedaço de código isolado e reutilizável que controla uma parte da interface do usuário do aplicativo.

Um componente em Angular é uma classe TypeScript decorada com o decorador @Component . Ele tem um modelo anexado e folhas de estilo CSS que formam a visualização do componente.

Angular 7, a versão mais recente do Angular foi lançada recentemente com novos recursos, principalmente em ferramentas e desempenho da CLI, como:

  • Prompts da CLI: Um comando comum como ng add e ng new agora pode solicitar ao usuário que escolha as funcionalidades a serem adicionadas a um projeto, como roteamento e formato de folhas de estilo, etc.
  • Adicionando rolagem ao Angular Material CDK (Component DevKit).
  • Adicionando suporte de arrastar e soltar ao Angular Material CDK.
  • Os projetos também são padronizados para usar pacotes de orçamento que avisarão os desenvolvedores quando seus aplicativos estiverem ultrapassando os limites de tamanho. Por padrão, os avisos são lançados quando o tamanho tem mais de 2 MB e os erros em 5 MB. Você também pode alterar esses limites em seu arquivo angular.json . etc.
Mais depois do salto! Continue lendo abaixo ↓

Apresentando o roteador angular

O Angular Router é um poderoso roteador JavaScript construído e mantido pela equipe principal do Angular que pode ser instalado a partir do pacote @angular/router . Ele fornece uma biblioteca de roteamento completa com a possibilidade de ter várias saídas de roteador, diferentes estratégias de correspondência de caminho, fácil acesso aos parâmetros de rota e proteções de rota para proteger os componentes contra acesso não autorizado.

O roteador Angular é uma parte central da plataforma Angular. Ele permite que os desenvolvedores criem aplicativos de página única com várias visualizações e permitem a navegação entre essas visualizações.

Vamos agora ver os conceitos essenciais do Roteador com mais detalhes.

A saída do roteador

O Router-Outlet é uma diretiva que está disponível na biblioteca do roteador onde o roteador insere o componente que é correspondido com base na URL do navegador atual. Você pode adicionar vários pontos de venda em seu aplicativo Angular, o que permite implementar cenários de roteamento avançados.

 <router-outlet></router-outlet>

Qualquer componente que seja correspondido pelo Roteador irá renderizá-lo como um irmão da tomada do Roteador.

Rotas e Caminhos

Rotas são definições (objetos) compostas de pelo menos um caminho e atributos de um componente (ou um caminho redirectTo). O caminho refere-se à parte da URL que determina uma visualização exclusiva que deve ser exibida e componente refere-se ao componente Angular que precisa ser associado a um caminho. Com base em uma definição de rota que fornecemos (por meio de um método estático RouterModule.forRoot(routes) ), o roteador é capaz de navegar o usuário para uma visualização específica.

Cada Route mapeia um path de URL para um componente.

O caminho pode estar vazio, o que denota o caminho padrão de um aplicativo e geralmente é o início do aplicativo.

O caminho pode ter uma string curinga ( ** ). O roteador selecionará essa rota se a URL solicitada não corresponder a nenhum caminho para as rotas definidas. Isso pode ser usado para exibir uma visualização “Não encontrada” ou redirecionar para uma visualização específica se nenhuma correspondência for encontrada.

Este é um exemplo de rota:

 { path: 'contacts', component: ContactListComponent}

Se esta definição de rota for fornecida à configuração do roteador, o roteador renderizará ContactListComponent quando a URL do navegador para o aplicativo da Web se tornar /contacts .

Estratégias de correspondência de rotas

O Angular Router fornece diferentes estratégias de correspondência de rotas. A estratégia padrão é simplesmente verificar se o URL do navegador atual é prefixado com o caminho .

Por exemplo, nossa rota anterior:

 { path: 'contacts', component: ContactListComponent}

Também poderia ser escrito como:

 { path: 'contacts',pathMatch: 'prefix', component: ContactListComponent}

O atributo patchMath especifica a estratégia de correspondência. Nesse caso, é o prefixo que é o padrão.

A segunda estratégia de correspondência está cheia . Quando for especificado para uma rota, o roteador verificará se o caminho é exatamente igual ao caminho da URL do navegador atual:

 { path: 'contacts',pathMatch: 'full', component: ContactListComponent}

Parâmetros de rota

Criar rotas com parâmetros é um recurso comum em aplicativos da web. O Angular Router permite acessar os parâmetros de diferentes maneiras:

  • Usando o serviço ActivatedRoute,
  • Usando o observável ParamMap disponível a partir da v4.

Você pode criar um parâmetro de rota usando a sintaxe de dois pontos . Esta é uma rota de exemplo com um parâmetro id :

 { path: 'contacts/:id', component: ContactDetailComponent}

Guardas de Rota

Um protetor de rota é um recurso do Angular Router que permite aos desenvolvedores executar alguma lógica quando uma rota é solicitada e, com base nessa lógica, permite ou nega o acesso do usuário à rota. É comumente usado para verificar se um usuário está logado e tem a autorização antes que ele possa acessar uma página.

Você pode adicionar um protetor de rota implementando a interface CanActivate disponível no pacote @angular/router e estendendo o método canActivate() que contém a lógica para permitir ou negar acesso à rota. Por exemplo, o seguinte guarda sempre permitirá o acesso a uma rota:

 class MyGuard implements CanActivate { canActivate() { return true; } }

Você pode então proteger uma rota com o guarda usando o atributo canActivate :

 { path: 'contacts/:id, canActivate:[MyGuard], component: ContactDetailComponent}

Diretiva de navegação

O Angular Router fornece a diretiva routerLink para criar links de navegação. Essa diretiva usa o caminho associado ao componente para o qual navegar. Por exemplo:

 <a [routerLink]="'/contacts'">Contacts</a>

Várias saídas e rotas auxiliares

O Angular Router suporta várias tomadas no mesmo aplicativo.

Um componente tem uma rota primária associada e pode ter rotas auxiliares. As rotas auxiliares permitem que os desenvolvedores naveguem em várias rotas ao mesmo tempo.

Para criar uma rota auxiliar, você precisará de uma saída de roteador nomeada onde o componente associado à rota auxiliar será exibido.

 <router-outlet></router-outlet> <router-outlet name="outlet1"></router-outlet>
  • A saída sem nome é a saída primária.
  • Todas as tomadas devem ter um nome, exceto a tomada principal.

Você pode então especificar a saída onde deseja renderizar seu componente usando o atributo outlet:

 { path: "contacts", component: ContactListComponent, outlet: "outlet1" }

Criando um projeto de demonstração do Angular 7

Nesta seção, veremos um exemplo prático de como configurar e trabalhar com o Angular Router. Você pode ver a demonstração ao vivo que criaremos e o repositório GitHub para o projeto.

Instalando o Angular CLI v7

A CLI Angular requer Node 8.9+ , com NPM 5.5.1+ . Você precisa ter esses requisitos instalados em seu sistema e executar o seguinte comando para instalar a versão mais recente do Angular CLI:

 $ npm install -g @angular/cli

Isso instalará a CLI Angular globalmente.

Instalando o Angular CLI v7
Instalando o Angular CLI v7 (visualização grande)

Nota : Você pode querer usar o sudo para instalar pacotes globalmente, dependendo da sua configuração do npm.

Criando um projeto Angular 7

Criar um novo projeto está a um comando de distância, você só precisa executar o seguinte comando:

 $ ng new angular7-router-demo

A CLI perguntará se você gostaria de adicionar roteamento (digite N para Não porque veremos como podemos adicionar roteamento manualmente) e qual formato de folha de estilo você gostaria de usar, escolha CSS, a primeira opção e pressione Enter . A CLI criará uma estrutura de pastas com os arquivos necessários e instalará as dependências necessárias do projeto.

Criando um serviço de back-end falso

Como não temos um back-end real para interagir, criaremos um back-end falso usando a biblioteca angular-in-memory-web-api , que é uma API da Web na memória para demonstrações e testes Angular que emula operações CRUD em uma API REST.

Ele funciona interceptando as solicitações HttpClient enviadas ao servidor remoto e as redireciona para um armazenamento de dados local na memória que precisamos criar.

Para criar um back-end falso, precisamos seguir os próximos passos:

  1. Primeiro, instalamos o módulo angular-in-memory-web-api ,
  2. Em seguida, criamos um serviço que retorna dados falsos,
  3. Por fim, configure o aplicativo para usar o back-end falso.

No seu terminal, execute o seguinte comando para instalar o módulo angular-in-memory-web-api do npm:

 $ npm install --save angular-in-memory-web-api

Em seguida, gere um serviço de back-end usando:

 $ ng gs backend

Abra o arquivo src/app/backend.service.ts e importe InMemoryDbService do módulo angular-in-memory-web-api :

 import {InMemoryDbService} from 'angular-in-memory-web-api'

A classe de serviço precisa implementar InMemoryDbService e então substituir o método createDb() :

 @Injectable({ providedIn: 'root' }) export class BackendService implements InMemoryDbService{ constructor() { } createDb(){ let contacts = [ { id: 1, name: 'Contact 1', email: '[email protected]' }, { id: 2, name: 'Contact 2', email: '[email protected]' }, { id: 3, name: 'Contact 3', email: '[email protected]' }, { id: 4, name: 'Contact 4', email: '[email protected]' } ]; return {contacts}; } }

Simplesmente criamos uma matriz de contatos e os devolvemos. Cada contato deve ter um id.

Finalmente, simplesmente precisamos importar InMemoryWebApiModule para o arquivo app.module.ts e fornecer nosso falso serviço de back-end.

 import { InMemoryWebApiModule } from “angular-in-memory-web-api”; import { BackendService } from “./backend.service”; /* ... */ @NgModule({ declarations: [ /*...*/ ], imports: [ /*...*/ InMemoryWebApiModule.forRoot(BackendService) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

Em seguida, crie um ContactService que encapsule o código para trabalhar com contatos:

 $ ng gs contact

Abra o arquivo src/app/contact.service.ts e atualize-o para que fique semelhante ao seguinte código:

 import { Injectable } from '@angular/core'; import { HttpClient } from “@angular/common/http”; @Injectable({ providedIn: 'root' }) export class ContactService { API_URL: string = "/api/"; constructor(private http: HttpClient) { } getContacts(){ return this.http.get(this.API_URL + 'contacts') } getContact(contactId){ return this.http.get(`${this.API_URL + 'contacts'}/${contactId}`) } }

Adicionamos dois métodos:

  • getContacts()
    Para obter todos os contatos.
  • getContact()
    Para obter um contato por id.

Você pode definir o API_URL para qualquer URL, pois não usaremos um back-end real. Todas as solicitações serão interceptadas e enviadas para o back-end na memória.

Criando nossos componentes angulares

Antes de podermos ver como usar os diferentes recursos do roteador, vamos primeiro criar vários componentes em nosso projeto.

Vá até o seu terminal e execute os seguintes comandos:

 $ ng gc contact-list $ ng gc contact-detail

Isso gerará dois componentes ContactListComponent e ContactDetailComponent e os adicionará ao módulo principal do aplicativo.

Configurando o roteamento

Na maioria dos casos, você usará a CLI do Angular para criar projetos com configuração de roteamento, mas neste caso, vamos adicioná-lo manualmente para que possamos ter uma ideia melhor de como o roteamento funciona no Angular.

Adicionando o módulo de roteamento

Precisamos adicionar AppRoutingModule que conterá nossas rotas de aplicativos e uma saída de roteador onde o Angular inserirá o componente atualmente correspondente dependendo da URL atual do navegador.

Veremos:

  • Como criar um Módulo Angular para roteamento e importá-lo;
  • Como adicionar rotas a diferentes componentes;
  • Como adicionar a tomada do roteador.

Primeiro, vamos começar criando um módulo de roteamento em um arquivo app-routing.module.ts . Dentro do src/app crie o arquivo usando:

 $ cd angular7-router-demo/src/app $ touch app-routing.module.ts

Abra o arquivo e adicione o seguinte código:

 import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = []; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }

Começamos importando o NgModule do pacote @angular/core que é um decorador TypeScript usado para criar um módulo Angular.

Também importamos as classes RouterModule e Routes do pacote @angular/router . RouterModule fornece métodos estáticos como RouterModule.forRoot() para passar um objeto de configuração para o roteador.

Em seguida, definimos um array de routes constantes do tipo Routes que será usado para armazenar informações para cada rota.

Por fim, criamos e exportamos um módulo chamado AppRoutingModule (você pode chamá-lo como quiser) que é simplesmente uma classe TypeScript decorada com o decorador @NgModule que recebe algum objeto de meta-informação. No atributo imports deste objeto, chamamos o método estático RouterModule.forRoot(routes) com o array de rotas como parâmetro. No array de exports adicionamos o RouterModule .

Importando o módulo de roteamento

Em seguida, precisamos importar esse roteamento de módulo para o módulo principal do aplicativo que reside no arquivo src/app/app.module.ts :

 import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

Importamos o AppRoutingModule de ./app-routing.module e o adicionamos no array imports do módulo principal.

Adicionando a saída do roteador

Finalmente, precisamos adicionar a tomada do roteador. Abra o arquivo src/app/app.component.html que contém o modelo de aplicativo principal e adicione o componente <router-outlet> :

 <router-outlet></router-outlet>

É aqui que o Angular Router renderizará o componente que corresponde ao caminho do navegador atual.

Essas são todas as etapas que precisamos seguir para configurar manualmente o roteamento dentro de um projeto Angular.

Criando Rotas

Agora, vamos adicionar rotas aos nossos dois componentes. Abra o arquivo src/app/app-routing.module.ts e adicione as seguintes rotas ao array de routes :

 const routes: Routes = [ {path: 'contacts' , component: ContactListComponent}, {path: 'contact/:id' , component: ContactDetailComponent} ];

Certifique-se de importar os dois componentes no módulo de roteamento:

 import { ContactListComponent } from './contact-list/contact-list.component'; import { ContactDetailComponent } from './contact-detail/contact-detail.component';

Agora podemos acessar os dois componentes dos caminhos /contacts e contact/:id .

Adicionando links de navegação

Em seguida, vamos adicionar links de navegação ao nosso modelo de aplicativo usando a diretiva routerLink . Abra o src/app/app.component.html e adicione o seguinte código na parte superior da tomada do roteador:

 <h2><a [routerLink] = "'/contacts'">Contacts</a></h2>

Em seguida, precisamos exibir a lista de contatos em ContactListComponent . Abra o src/app/contact-list.component.ts e adicione o seguinte código:

 import { Component, OnInit } from '@angular/core'; import { ContactService } from '../contact.service'; @Component({ selector: 'app-contact-list', templateUrl: './contact-list.component.html', styleUrls: ['./contact-list.component.css'] }) export class ContactListComponent implements OnInit { contacts: any[] = []; constructor(private contactService: ContactService) { } ngOnInit() { this.contactService.getContacts().subscribe((data : any[])=>{ console.log(data); this.contacts = data; }) } }

Criamos uma matriz de contacts para armazenar os contatos. Em seguida, injetamos ContactService e chamamos o método getContacts() da instância (no evento de ciclo de vida ngOnInit ) para obter contatos e atribuí-los à matriz de contacts .

Em seguida, abra o arquivo src/app/contact-list/contact-list.component.html e adicione:

 <table> <tr> <th>Name</th> <th>Email</th> <th>Actions</th> </tr> <tr *ngFor="let contact of contacts" > <td>{{ contact.name }}</td> <td>{{ contact.email }}</td> <td> <a [routerLink]="['/contact', contact.id]">Go to details</a> </td> </tr> </table>

Percorremos os contatos e exibimos o nome e o e-mail de cada contato. Também criamos um link para o componente de detalhes de cada contato usando a diretiva routerLink .

Esta é uma captura de tela do componente:

Lista de contatos
Lista de contatos (visualização grande)

Quando clicarmos no link Ir para detalhes , ele nos levará para ContactDetailsComponent . A rota tem um parâmetro id , vamos ver como podemos acessá-la do nosso componente.

Abra o arquivo src/app/contact-detail/contact-detail.component.ts e altere o código para se parecer com o seguinte código:

 import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ContactService } from '../contact.service'; @Component({ selector: 'app-contact-detail', templateUrl: './contact-detail.component.html', styleUrls: ['./contact-detail.component.css'] }) export class ContactDetailComponent implements OnInit { contact: any; constructor(private contactService: ContactService, private route: ActivatedRoute) { } ngOnInit() { this.route.paramMap.subscribe(params => { console.log(params.get('id')) this.contactService.getContact(params.get('id')).subscribe(c =>{ console.log(c); this.contact = c; }) }); } }

Injetamos ContactService e ActivatedRoute no componente. No evento de ciclo de vida ngOnInit() , recuperamos o parâmetro id que será passado da rota e o usamos para obter os detalhes do contato que atribuímos a um objeto de contact .

Abra o arquivo src/app/contact-detail/contact-detail.component.html e adicione:

 <h1> Contact # {{contact.id}}</h1> <p> Name: {{contact.name}} </p> <p> Email: {{contact.email}} </p> 
Detalhes do contato
Detalhes de contato (visualização grande)

Quando visitamos nosso aplicativo pela primeira vez de 127.0.0.1:4200/ , a saída não renderiza nenhum componente, então vamos redirecionar o caminho vazio para o caminho de contacts adicionando a seguinte rota ao array de rotas:

 {path: '', pathMatch: 'full', redirectTo: 'contacts'}

Queremos corresponder ao caminho vazio exato, é por isso que especificamos a estratégia de correspondência completa .

Conclusão

Neste tutorial, vimos como usar o Angular Router para adicionar roteamento e navegação em nosso aplicativo. Vimos conceitos diferentes como saída do roteador, rotas e caminhos e criamos uma demonstração para mostrar praticamente os diferentes conceitos. Você pode acessar o código deste repositório.