🅰️ Treinamento Angular Completo
Do Zero ao Profissional - Aprenda o framework da Google para criar aplicações web modernas em qualquer sistema operacional. Mais de 2.000 linhas de conteúdo detalhado!
📌 Neste Treinamento você vai aprender (15 Módulos Completos):
Módulo 1: Introdução ao Angular
📖 O que é Angular?
Angular é um framework de desenvolvimento front-end mantido pela Google, usado para criar aplicações web dinâmicas, escaláveis e de alta performance. Foi lançado em 2016 como uma reescrita completa do AngularJS (versão 1.x), trazendo uma arquitetura baseada em componentes e utilizando TypeScript como linguagem principal.
🔍 Angular vs AngularJS - Qual a diferença?
- AngularJS (v1.x): Framework JavaScript, baseado em controllers e $scope, arquitetura MVC
- Angular (2+): Framework TypeScript, baseado em componentes, mais performático, mobile-ready
- Versão atual: Angular 19 (2025/2026) - suporte LTS (Long Term Support) garantido pela Google
- Principais melhorias: Ivy renderer, standalone components, signals, melhor performance
💡 História do Angular
O Angular foi criado por Miško Hevery e Adam Abrons em 2009 como um projeto paralelo. Em 2010, a Google começou a patrocinar o projeto. Em 2016, uma versão completamente reescrita foi lançada como Angular 2, marcando uma mudança radical na arquitetura. Atualmente, o Angular é um dos frameworks mais utilizados no mundo, com milhões de desenvolvedores e milhares de aplicações em produção.
🎯 Por que usar Angular?
✅ TypeScript
Tipagem estática, melhor experiência de desenvolvimento, código mais seguro e fácil de manter.
✅ Componentes
Arquitetura baseada em componentes reutilizáveis, facilitando a organização do código.
✅ Injeção de Dependência
Framework nativo para gerenciar dependências, promovendo desacoplamento e testabilidade.
✅ CLI Poderosa
Ferramenta de linha de comando que agiliza o desenvolvimento, geração de código e build.
✅ Ecossistema Completo
Router, HTTP Client, Forms, Animations, PWA, SSR, tudo incluso no framework.
✅ Suporte Google
Framework empresarial com suporte de longo prazo, utilizado por grandes empresas mundialmente.
🏗️ Arquitetura Angular
┌─────────────────────────────────────────────────────────────────┐ │ Módulos (NgModule) │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ Componentes │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ Template │ │ Classe │ │ │ │ │ │ (HTML) │◄──►│ (TypeScript) │ │ │ │ │ └─────────────────┘ └─────────────────┘ │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ Estilos │ │ Metadados │ │ │ │ │ │ (CSS/SCSS) │ │ @Component │ │ │ │ │ └─────────────────┘ └─────────────────┘ │ │ │ └───────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Serviços │ │ Diretivas │ │ Pipes │ │ │ │ (Services) │ │ (Directives) │ │ (Filters) │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Router │ │ HTTPClient │ │ Animations │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────────┘
📌 Componentes Standalone (Angular 14+)
A partir do Angular 14, é possível criar componentes sem a necessidade de NgModules, simplificando a estrutura e reduzindo boilerplate. Os componentes standalone são a abordagem recomendada para novos projetos.
🔄 Ciclo de Vida do Componente
| Fase | Método | Descrição |
|---|---|---|
| Criação | constructor() | Primeiro a ser executado, ideal para injeção de dependências |
| Inicialização | ngOnInit() | Executado após a criação, ideal para carregar dados iniciais |
| Verificação | ngDoCheck() | Executado a cada ciclo de detecção de mudanças |
| Conteúdo | ngAfterContentInit() | Após projetar conteúdo no componente |
| Visualização | ngAfterViewInit() | Após inicializar a view do componente |
| Destruição | ngOnDestroy() | Limpeza antes de remover o componente |
Módulo 2: Setup do Ambiente - Windows, Mac e Linux
📋 Pré-requisitos (Todos os Sistemas Operacionais)
Antes de começar a programar em Angular, você precisa ter instalado no seu computador:
- Node.js (versão LTS 18.x, 20.x ou superior) - nodejs.org
- npm (Node Package Manager) - já incluso na instalação do Node.js
- Visual Studio Code (recomendado) - code.visualstudio.com
- Git (opcional, mas recomendado para versionamento) - git-scm.com
⚠️ Verifique sua versão do Node.js
Angular requer Node.js versão 18.10.0 ou superior. Para verificar sua versão, abra o terminal e digite:
node --version
Se a versão for inferior, atualize o Node.js antes de prosseguir.
📥 Instalação do Node.js por Sistema Operacional
🔹 MÉTODO 1: Instalador Oficial (Recomendado para iniciantes)
1. Acesse https://nodejs.org
2. Baixe a versão LTS (arquivo .msi - Windows Installer)
3. Execute o instalador baixado
4. Clique em "Next" até finalizar (mantenha as opções padrão)
5. Reinicie o terminal após a instalação
🔹 MÉTODO 2: Via Chocolatey (para usuários avançados)
choco install nodejs-lts
🔹 MÉTODO 3: Via Winget (Windows 11 / Windows 10 atualizado)
winget install OpenJS.NodeJS.LTS
🔹 Verificar instalação:
node --version
npm --version
⚠️ Problema comum no Windows: Política de Execução
Se ao tentar executar comandos npm/ng aparecer o erro "cannot be loaded because running scripts is disabled", execute no PowerShell como Administrador:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Depois, feche e abra o terminal novamente.
💡 Dica Windows: WSL2 (Windows Subsystem for Linux)
Para uma experiência mais próxima do Linux, você pode instalar o WSL2 e rodar o Angular dentro de uma distribuição Ubuntu. Isso é especialmente útil se você trabalha com equipes que usam Linux/macOS.
🔹 MÉTODO 1: Instalador Oficial (mais simples)
1. Acesse https://nodejs.org
2. Baixe a versão LTS para macOS (arquivo .pkg)
3. Execute o instalador e siga as instruções
4. Reinicie o terminal
🔹 MÉTODO 2: Via Homebrew (recomendado para desenvolvedores)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install node
🔹 MÉTODO 3: Via nvm (Node Version Manager) - gerencia múltiplas versões
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install --lts
nvm use --lts
🔹 Verificar instalação:
node --version
npm --version
🍎 Dica para Mac: Permissões
Se encontrar problemas de permissão ao instalar pacotes globais, use sudo antes do comando:
sudo npm install -g @angular/cli
Ou ajuste as permissões da pasta global do npm:
sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
🔹 Ubuntu/Debian (via repositório oficial)
sudo apt update
sudo apt install nodejs npm -y
🔹 Ubuntu/Debian (NodeSource - versão mais recente)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
🔹 Via nvm (recomendado - funciona em todas distribuições)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Reinicie o terminal
nvm install --lts
nvm use --lts
🔹 Verificar instalação:
node --version
npm --version
🐧 Dica para Linux: Permissões globais
Para evitar usar sudo ao instalar pacotes npm globalmente, configure o npm para usar um diretório pessoal:
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
🔹 Fedora / RHEL / CentOS
sudo dnf install nodejs npm -y
🔹 Para versão mais recente (NodeSource)
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo dnf install nodejs -y
🔹 Arch Linux / Manjaro
sudo pacman -S nodejs npm
🔹 Via nvm (recomendado)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install --lts
🔹 Verificar instalação:
node --version
npm --version
🅰️ Instalando Angular CLI (Comum a todos OS)
# Instalar Angular CLI globalmente (mesmo comando em todos OS)
npm install -g @angular/cli
# Verificar instalação
ng version
# Saída esperada:
# Angular CLI: 19.0.0
# Node: 20.10.0
# Package Manager: npm 10.2.0
# OS: (windows/mac/linux)
💡 Curiosidade: Angular CLI
O Angular CLI (Command Line Interface) foi criado para padronizar e agilizar o desenvolvimento. Ele gerencia desde a criação do projeto até o build para produção, além de gerar componentes, serviços, módulos e outras estruturas com um único comando. É uma das ferramentas mais poderosas do ecossistema Angular!
🚀 Criando seu primeiro projeto Angular
# Criar novo projeto (mesmo comando em todos OS)
ng meu-primeiro-projeto
# Durante a criação, responda:
# ✅ Would you like to add Angular routing? Yes (para projetos com múltiplas páginas)
# ✅ Which stylesheet format? CSS (ou SCSS/Sass se preferir)
# ✅ Do you want to enable Server-Side Rendering? No (para começar)
# Entrar na pasta do projeto
cd meu-primeiro-projeto
# Executar o servidor de desenvolvimento
ng serve
# Abrir no navegador: http://localhost:4200
# Para parar o servidor: Ctrl + C
🎯 Dica: ng serve --open
Use ng serve --open (ou ng serve -o) para abrir automaticamente o navegador quando o servidor iniciar.
📁 Estrutura do Projeto Angular
meu-primeiro-projeto/ ├── .angular/ # Configurações do Angular ├── .vscode/ # Configurações do VS Code ├── node_modules/ # Dependências do projeto (não versionar!) ├── public/ # Arquivos públicos (favicon, assets) ├── src/ # Código fonte da aplicação │ ├── app/ # Componentes, serviços e módulos │ │ ├── app.component.css # Estilos do componente principal │ │ ├── app.component.html # Template do componente principal │ │ ├── app.component.spec.ts # Testes do componente principal │ │ ├── app.component.ts # Lógica do componente principal │ │ ├── app.config.ts # Configuração da aplicação (standalone) │ │ └── app.routes.ts # Configuração de rotas │ ├── assets/ # Imagens, fonts, etc │ ├── index.html # Página principal │ ├── main.ts # Ponto de entrada da aplicação │ └── styles.css # Estilos globais ├── .editorconfig # Configuração do editor ├── .gitignore # Arquivos ignorados pelo Git ├── angular.json # Configuração do workspace Angular ├── package.json # Dependências e scripts ├── tsconfig.json # Configuração do TypeScript └── README.md # Documentação do projeto
🔧 Comandos Angular CLI Essenciais
Módulo 3: Fundamentos TypeScript
📘 O que é TypeScript?
TypeScript é um superset do JavaScript que adiciona tipagem estática e recursos modernos como interfaces, generics, decorators e muito mais. Angular é escrito inteiramente em TypeScript, e entender seus conceitos é fundamental para se tornar um desenvolvedor Angular proficiente.
🔍 JavaScript vs TypeScript - Exemplo Prático
// ========== JAVASCRIPT (sem tipos) ==========
function soma(a, b) {
return a + b;
}
console.log(soma(5, "10")); // Retorna "510" - Comportamento inesperado!
// ========== TYPESCRIPT (com tipos) ==========
function soma(a: number, b: number): number {
return a + b;
}
console.log(soma(5, "10")); // ❌ ERRO: Argumento do tipo 'string' não é atribuível a 'number'
// Isso detecta o erro ANTES de executar o código!
🔤 Tipos Básicos no TypeScript
// ========== Tipos Primitivos ==========
let nome: string = "João Silva";
let idade: number = 25;
let ativo: boolean = true;
let dados: any = "pode ser qualquer coisa"; // Evitar usar, quebra a tipagem
// ========== Arrays ==========
let numeros: number[] = [1, 2, 3, 4, 5];
let nomes: Array<string> = ["Ana", "Pedro", "Maria"];
// ========== Tuplas ==========
let pessoa: [string, number] = ["João", 30];
// ========== Enums ==========
enum Status {
Pendente = "PENDENTE",
EmAndamento = "EM_ANDAMENTO",
Concluido = "CONCLUIDO"
}
let meuStatus: Status = Status.EmAndamento;
// ========== Union Types ==========
let id: string | number;
id = "ABC123";
id = 456; // Também válido
// ========== Type Aliases ==========
type ID = string | number;
type UsuarioType = {
id: ID;
nome: string;
email: string;
};
📦 Interfaces e Classes
// ========== Interfaces ==========
interface Produto {
id: number;
nome: string;
preco: number;
categoria?: string; // Opcional
readonly codigo: string; // Somente leitura
}
const produto: Produto = {
id: 1,
nome: "Notebook",
preco: 2500,
codigo: "NB-001"
};
// ========== Classes ==========
class Usuario {
// Modificadores de acesso: public, private, protected
private _id: number;
public nome: string;
protected email: string;
constructor(id: number, nome: string, email: string) {
this._id = id;
this.nome = nome;
this.email = email;
}
// Getter
get id(): number {
return this._id;
}
// Método
exibirInfo(): string {
return `${this.nome} (${this.email})`;
}
// Método estático
static criarAdmin(): Usuario {
return new Usuario(0, "Admin", "admin@empresa.com");
}
}
// Herança
class Cliente extends Usuario {
private pontos: number = 0;
adicionarPontos(valor: number): void {
this.pontos += valor;
}
// Sobrescrita de método
exibirInfo(): string {
return `${super.exibirInfo()} - Pontos: ${this.pontos}`;
}
}
⚙️ Generics e Utilitários
// ========== Generics ==========
function identidade<T>(valor: T): T {
return valor;
}
let texto = identidade<string>("Olá");
let numero = identidade<number>(42);
// ========== Classe Genérica ==========
class Repositorio<T> {
private itens: T[] = [];
adicionar(item: T): void {
this.itens.push(item);
}
listar(): T[] {
return [...this.itens];
}
buscar(predicado: (item: T) => boolean): T | undefined {
return this.itens.find(predicado);
}
}
const repoUsuarios = new Repositorio<Usuario>();
repoUsuarios.adicionar(new Usuario(1, "João", "joao@email.com"));
// ========== Tipos Utilitários ==========
interface Config {
host: string;
port: number;
ssl: boolean;
}
// Partial - todos os campos opcionais
type ConfigParcial = Partial<Config>;
// Required - todos os campos obrigatórios
type ConfigObrigatoria = Required<Config>;
// Pick - seleciona campos específicos
type ConfigBasica = Pick<Config, "host" | "port">;
// Omit - omite campos específicos
type ConfigSemSSL = Omit<Config, "ssl">;
🎨 Decorators (Essenciais para Angular)
// Decorators são funções que adicionam metadados a classes, métodos ou propriedades
// Angular usa decorators extensivamente:
// @Component - Define um componente Angular
@Component({
selector: 'app-meu-componente',
templateUrl: './meu-componente.component.html',
styleUrls: ['./meu-componente.component.css']
})
export class MeuComponente { }
// @Injectable - Define um serviço injetável
@Injectable({
providedIn: 'root'
})
export class MeuServico { }
// @Input - Propriedade que recebe dados do componente pai
@Input() titulo: string;
// @Output - Evento que emite dados para o componente pai
@Output() evento = new EventEmitter<string>();
// @ViewChild - Referência a um elemento filho no template
@ViewChild('meuElemento') elemento: ElementRef;
Módulo 4: Componentes e Templates
🧩 Criando Componentes
# Usando Angular CLI (recomendado)
ng generate component MeuComponente
# ou forma abreviada
ng g c MeuComponente
# Para criar com arquivos específicos
ng g c MeuComponente --flat # Não cria pasta separada
ng g c MeuComponente --inline-template # Template inline
ng g c MeuComponente --inline-style # Estilos inline
ng g c MeuComponente --skip-tests # Não cria arquivo de teste
📄 Estrutura de um Componente
// meu-componente.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-meu-componente', // Nome da tag HTML
templateUrl: './meu-componente.component.html', // Template externo
styleUrls: ['./meu-componente.component.css'], // Estilos externos
// Ou template/estilos inline:
// template: `<h1>Olá Mundo!</h1>`,
// styles: [`h1 { color: red; }`]
})
export class MeuComponenteComponent implements OnInit {
// Propriedades do componente
titulo: string = "Meu Primeiro Componente!";
contador: number = 0;
// Input - recebe dados do componente pai
@Input() nomeUsuario: string = "";
// Output - envia eventos para o componente pai
@Output() contadorAlterado = new EventEmitter<number>();
// Construtor - injeta dependências
constructor() {
console.log("Componente criado!");
}
// Lifecycle hook - executado após a inicialização
ngOnInit(): void {
console.log("Componente inicializado!");
}
// Métodos do componente
incrementar(): void {
this.contador++;
this.contadorAlterado.emit(this.contador);
}
decrementar(): void {
this.contador--;
this.contadorAlterado.emit(this.contador);
}
resetar(): void {
this.contador = 0;
this.contadorAlterado.emit(this.contador);
}
}
🎨 Template HTML
<!-- meu-componente.component.html -->
<div class="componente-container">
<h2>{{ titulo }}</h2>
<div *ngIf="nomeUsuario">
<p>Bem-vindo(a), {{ nomeUsuario }}!</p>
</div>
<div class="contador-container">
<p>Contador atual: <strong>{{ contador }}</strong></p>
<div class="botoes">
<button (click)="decrementar()" [disabled]="contador === 0">-</button>
<button (click)="resetar()">Reset</button>
<button (click)="incrementar()">+</button>
</div>
</div>
</div>
🔗 Data Binding (Vinculação de Dados)
📌 Interpolação
Sintaxe: {{ expressao }}
<h1>Olá, {{ usuario.nome }}!</h1>
<p>Você tem {{ idade }} anos.</p>
📌 Property Binding
Sintaxe: [propriedade]="expressao"
<img [src]="imagemUrl">
<button [disabled]="isDesabilitado">Clique</button>
📌 Event Binding
Sintaxe: (evento)="metodo()"
<button (click)="salvar()">Salvar</button>
<input (keyup.enter)="buscar($event)">
📌 Two-way Binding
Sintaxe: [(ngModel)]="variavel"
<input [(ngModel)]="nome">
<p>Olá, {{ nome }}!</p>
⚠️ Requer importar FormsModule no módulo ou componente standalone.
🔄 Lifecycle Hooks
| Hook | Timing | Uso Comum |
|---|---|---|
ngOnChanges() | Quando um input property muda | Reagir a mudanças em @Input() |
ngOnInit() | Após o primeiro ngOnChanges | Inicializar dados, chamar APIs |
ngDoCheck() | A cada ciclo de detecção de mudanças | Detecção customizada |
ngAfterContentInit() | Após projetar conteúdo | Inicializar conteúdo projetado |
ngAfterContentChecked() | A cada verificação de conteúdo | Lógica após verificação |
ngAfterViewInit() | Após inicializar a view | Acessar elementos DOM |
ngAfterViewChecked() | A cada verificação da view | Lógica após verificação |
ngOnDestroy() | Antes de destruir o componente | Limpar recursos, unsubscribe |
// Exemplo prático de lifecycle hooks
export class MeuComponente implements OnInit, OnChanges, OnDestroy {
@Input() dados: any;
ngOnChanges(changes: SimpleChanges): void {
console.log('Input changed:', changes);
}
ngOnInit(): void {
console.log('Componente inicializado');
this.carregarDados();
}
ngOnDestroy(): void {
console.log('Componente destruído');
// Limpar subscriptions
this.subscription.unsubscribe();
}
}
Módulo 5: Diretivas Estruturais e de Atributo
🔧 Diretivas Estruturais
Diretivas estruturais modificam a estrutura do DOM (adicionam/removem elementos). São identificadas pelo asterisco (*).
// ========== *ngIf - Renderização Condicional ==========
<div *ngIf="usuarioLogado; else naoLogado">
<p>Bem-vindo, {{ usuario.nome }}!</p>
</div>
<ng-template #naoLogado>
<p>Faça login para continuar</p>
</ng-template>
// Versão com else if (Angular 17+)
@if (usuarioLogado) {
<p>Bem-vindo, {{ usuario.nome }}!</p>
} @else {
<p>Faça login</p>
}
// ========== *ngFor - Repetição ==========
<ul>
<li *ngFor="let item of lista; let i = index; let primeiro = first; let ultimo = last">
{{ i + 1 }} - {{ item.nome }}
<span *ngIf="primeiro"> (Primeiro)</span>
<span *ngIf="ultimo"> (Último)</span>
</li>
</ul>
// Versão Angular 17+ (@for)
@for (item of lista; track item.id; let i = $index) {
<li>{{ i + 1 }} - {{ item.nome }}</li>
} @empty {
<li>Nenhum item encontrado</li>
}
// ========== *ngSwitch - Múltiplas Condições ==========
<div [ngSwitch]="status">
<p *ngSwitchCase="'ativo'">✅ Status: Ativo</p>
<p *ngSwitchCase="'inativo'">⭕ Status: Inativo</p>
<p *ngSwitchCase="'pendente'">⏳ Status: Pendente</p>
<p *ngSwitchDefault>❓ Status desconhecido</p>
</div>
🎨 Diretivas de Atributo
Diretivas de atributo alteram a aparência ou comportamento de um elemento existente.
// ========== ngClass - Classes CSS Condicionais ==========
<div [ngClass]="{
'ativo': isAtivo,
'inativo': !isAtivo,
'destaque': isDestaque
}">
Conteúdo com classes dinâmicas
</div>
// Também pode usar string ou array
<div [ngClass]="'classe1 classe2'"></div>
<div [ngClass]="['classe1', 'classe2']"></div>
// ========== ngStyle - Estilos Inline Condicionais ==========
<div [ngStyle]="{
'color': corTexto,
'font-size': tamanhoFonte + 'px',
'background-color': isDestaque ? '#ff0' : '#fff'
}">
Texto estilizado dinamicamente
</div>
// ========== ngModel - Two-way Binding (FormsModule) ==========
<input [(ngModel)]="nome" placeholder="Digite seu nome">
<p>Olá, {{ nome }}!</p>
🛠️ Criando Diretivas Customizadas
// gerar diretiva: ng g directive destaque
import { Directive, ElementRef, Input, HostListener } from '@angular/core';
@Directive({
selector: '[appDestaque]',
standalone: true
})
export class DestaqueDirective {
@Input('appDestaque') cor: string = 'yellow';
constructor(private el: ElementRef) { }
@HostListener('mouseenter') onMouseEnter() {
this.destacar(this.cor);
}
@HostListener('mouseleave') onMouseLeave() {
this.destacar(null);
}
private destacar(cor: string | null) {
this.el.nativeElement.style.backgroundColor = cor;
}
}
// Uso no template:
<p appDestaque="lightblue">Passe o mouse aqui!</p>
Módulo 6: Serviços e Injeção de Dependência
🔌 O que são Serviços?
Serviços são classes que concentram lógica de negócio, compartilhamento de dados e comunicação com APIs. Eles são injetados nos componentes através do sistema de Injeção de Dependência (DI) do Angular.
✅ Vantagens dos Serviços:
- Separação de responsabilidades (componentes focam na view)
- Reutilização de código entre componentes
- Facilidade para testes unitários
- Singleton por escopo (compartilhamento de estado)
📄 Criando um Serviço
# Gerar serviço
ng generate service dados
# ou
ng g s dados
// dados.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject } from 'rxjs';
export interface Usuario {
id: number;
nome: string;
email: string;
}
@Injectable({
providedIn: 'root' // Disponível em toda aplicação (singleton)
})
export class DadosService {
private apiUrl = 'https://jsonplaceholder.typicode.com/users';
private usuariosSubject = new BehaviorSubject<Usuario[]>([]);
public usuarios$ = this.usuariosSubject.asObservable();
constructor(private http: HttpClient) { }
// Método que retorna Observable
listarUsuarios(): Observable<Usuario[]> {
return this.http.get<Usuario[]>(this.apiUrl);
}
// Método que atualiza o BehaviorSubject
atualizarUsuarios(usuarios: Usuario[]): void {
this.usuariosSubject.next(usuarios);
}
// Método com callback
buscarUsuario(id: number, callback: (usuario: Usuario) => void): void {
this.http.get<Usuario>(`${this.apiUrl}/${id}`).subscribe({
next: (usuario) => callback(usuario),
error: (err) => console.error('Erro:', err)
});
}
// Método com Promise
async criarUsuario(usuario: Partial<Usuario>): Promise<Usuario> {
try {
return await this.http.post<Usuario>(this.apiUrl, usuario).toPromise();
} catch (error) {
throw new Error('Erro ao criar usuário');
}
}
}
💉 Injeção de Dependência
// Injetando serviço no componente
import { Component, OnInit } from '@angular/core';
import { DadosService, Usuario } from './dados.service';
@Component({
selector: 'app-usuarios',
template: `
<div *ngIf="carregando">Carregando...</div>
<ul>
<li *ngFor="let usuario of usuarios">
{{ usuario.nome }} - {{ usuario.email }}
</li>
</ul>
`
})
export class UsuariosComponent implements OnInit {
usuarios: Usuario[] = [];
carregando = false;
// Injeção via construtor
constructor(private dadosService: DadosService) { }
ngOnInit() {
this.carregando = true;
this.dadosService.listarUsuarios().subscribe({
next: (dados) => {
this.usuarios = dados;
this.carregando = false;
},
error: (err) => {
console.error(err);
this.carregando = false;
}
});
}
}
🏭 Hierarquia de Injeção
providedIn: 'root'
Singleton global - uma única instância para toda aplicação. Ideal para serviços que compartilham dados globalmente.
providedIn: 'platform'
Compartilhado entre múltiplas aplicações na mesma página. Raramente usado.
providedIn: 'any'
Uma instância por módulo que importa o serviço.
providers no componente
Uma instância por componente (cada instância do componente tem seu próprio serviço).
Módulo 7: Roteamento Avançado
🛣️ Configuração de Rotas
// app.routes.ts (Angular standalone)
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { SobreComponent } from './sobre/sobre.component';
import { ContatoComponent } from './contato/contato.component';
import { ProdutoDetalheComponent } from './produto-detalhe/produto-detalhe.component';
import { AuthGuard } from './guards/auth.guard';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'sobre', component: SobreComponent },
{ path: 'contato', component: ContatoComponent },
{
path: 'produtos',
loadChildren: () => import('./produtos/produtos.routes').then(m => m.produtosRoutes)
},
{
path: 'admin',
canActivate: [AuthGuard],
loadChildren: () => import('./admin/admin.routes').then(m => m.adminRoutes)
},
{ path: 'produto/:id', component: ProdutoDetalheComponent },
{ path: 'busca', component: BuscaComponent },
{ path: '**', redirectTo: '' } // Rota curinga (404)
];
🎯 Template com Rotas
<!-- app.component.html -->
<nav>
<a routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
Home
</a>
<a routerLink="/sobre" routerLinkActive="active">Sobre</a>
<a routerLink="/contato" routerLinkActive="active">Contato</a>
<a [routerLink]="['/produto', produtoId]">Produto</a>
</nav>
<router-outlet></router-outlet>
🔐 Route Guards (Proteção de Rotas)
// auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(private router: Router, private authService: AuthService) { }
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean {
if (this.authService.isAuthenticated()) {
return true;
}
// Redirecionar para login com returnUrl
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
return false;
}
}
// Uso no componente
import { ActivatedRoute, Router } from '@angular/router';
export class MeuComponente {
constructor(
private route: ActivatedRoute,
private router: Router
) { }
navegarParaDetalhe(id: number) {
this.router.navigate(['/produto', id], {
queryParams: { origem: 'lista', pagina: 1 },
fragment: 'comentarios'
});
}
obterParametros() {
// Parâmetros da rota
const id = this.route.snapshot.params['id'];
// Query params
this.route.queryParams.subscribe(params => {
console.log(params['origem']);
});
}
}
Módulo 8: Formulários Reativos e Template-driven
📝 Formulários Reativos (Reactive Forms)
Abordagem baseada em código, mais robusta e escalável. Recomendada para formulários complexos.
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators, AbstractControl } from '@angular/forms';
@Component({
selector: 'app-root',
template: `
<form [formGroup]="cadastroForm" (ngSubmit)="onSubmit()">
<div>
<label>Nome:</label>
<input formControlName="nome">
<div *ngIf="nome?.invalid && nome?.touched">
<small *ngIf="nome?.errors?.['required']">Nome é obrigatório</small>
<small *ngIf="nome?.errors?.['minlength']">
Mínimo de 3 caracteres
</small>
</div>
</div>
<div>
<label>Email:</label>
<input formControlName="email" type="email">
<div *ngIf="email?.invalid && email?.touched">
<small *ngIf="email?.errors?.['required']">Email é obrigatório</small>
<small *ngIf="email?.errors?.['email']">Email inválido</small>
</div>
</div>
<div>
<label>Idade:</label>
<input formControlName="idade" type="number">
</div>
<div formArrayName="telefones">
<h4>Telefones</h4>
<div *ngFor="let tel of telefones.controls; let i=index">
<input [formControlName]="i" placeholder="Telefone {{i+1}}">
<button type="button" (click)="removerTelefone(i)">Remover</button>
</div>
<button type="button" (click)="adicionarTelefone()">+ Adicionar Telefone</button>
</div>
<button type="submit" [disabled]="cadastroForm.invalid">Cadastrar</button>
</form>
`
})
export class AppComponent implements OnInit {
cadastroForm: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit() {
this.cadastroForm = this.fb.group({
nome: ['', [Validators.required, Validators.minLength(3)]],
email: ['', [Validators.required, Validators.email]],
idade: [null, [Validators.min(18), Validators.max(100)]],
telefones: this.fb.array([])
});
}
get nome() { return this.cadastroForm.get('nome'); }
get email() { return this.cadastroForm.get('email'); }
get telefones() { return this.cadastroForm.get('telefones') as FormArray; }
adicionarTelefone() {
this.telefones.push(this.fb.control('', Validators.pattern(/^\d{10,11}$/)));
}
removerTelefone(index: number) {
this.telefones.removeAt(index);
}
onSubmit() {
if (this.cadastroForm.valid) {
console.log(this.cadastroForm.value);
}
}
}
📄 Validações Customizadas
// validators/custom.validators.ts
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
export class CustomValidators {
static senhaForte(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const value = control.value;
if (!value) return null;
const hasUpperCase = /[A-Z]/.test(value);
const hasLowerCase = /[a-z]/.test(value);
const hasNumber = /[0-9]/.test(value);
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(value);
const isValidLength = value.length >= 8;
const passwordValid = hasUpperCase && hasLowerCase && hasNumber && hasSpecialChar && isValidLength;
return !passwordValid ? { senhaForte: true } : null;
};
}
static compararSenhas(senhaControlName: string, confirmarSenhaControlName: string): ValidatorFn {
return (group: AbstractControl): ValidationErrors | null => {
const senha = group.get(senhaControlName)?.value;
const confirmar = group.get(confirmarSenhaControlName)?.value;
return senha === confirmar ? null : { senhasDiferentes: true };
};
}
static cpfValido(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const cpf = control.value;
if (!cpf) return null;
// Lógica de validação de CPF
const isValid = this.validarCPF(cpf);
return isValid ? null : { cpfInvalido: true };
};
}
private static validarCPF(cpf: string): boolean {
// Implementação da validação de CPF
return true;
}
}
Módulo 9: HTTP Client e APIs REST
🌐 Configurando HTTP Client
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withInterceptors, withFetch } from '@angular/common/http';
import { authInterceptor } from './interceptors/auth.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withFetch(), // Usar Fetch API (mais moderno)
withInterceptors([authInterceptor]) // Interceptors
)
]
};
📡 Serviço para Consumir API
// api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { Observable, throwError, retry, catchError, timeout, map } from 'rxjs';
export interface Usuario {
id: number;
name: string;
email: string;
username: string;
}
@Injectable({ providedIn: 'root' })
export class ApiService {
private baseUrl = 'https://jsonplaceholder.typicode.com';
constructor(private http: HttpClient) { }
// GET com parâmetros
getUsuarios(limite?: number, pagina?: number): Observable<Usuario[]> {
let params = new HttpParams();
if (limite) params = params.set('_limit', limite.toString());
if (pagina) params = params.set('_page', pagina.toString());
return this.http.get<Usuario[]>(`${this.baseUrl}/users`, { params })
.pipe(
retry(3), // Tentar novamente em caso de erro
timeout(10000), // Timeout de 10 segundos
catchError(this.handleError)
);
}
// GET por ID
getUsuario(id: number): Observable<Usuario> {
return this.http.get<Usuario>(`${this.baseUrl}/users/${id}`)
.pipe(
map(usuario => ({
...usuario,
name: usuario.name.toUpperCase()
})),
catchError(this.handleError)
);
}
// POST - Criar recurso
criarUsuario(usuario: Partial<Usuario>): Observable<Usuario> {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem('token')
});
return this.http.post<Usuario>(`${this.baseUrl}/users`, usuario, { headers })
.pipe(catchError(this.handleError));
}
// PUT - Atualizar completo
atualizarUsuario(id: number, usuario: Usuario): Observable<Usuario> {
return this.http.put<Usuario>(`${this.baseUrl}/users/${id}`, usuario)
.pipe(catchError(this.handleError));
}
// PATCH - Atualizar parcial
patchUsuario(id: number, changes: Partial<Usuario>): Observable<Usuario> {
return this.http.patch<Usuario>(`${this.baseUrl}/users/${id}`, changes)
.pipe(catchError(this.handleError));
}
// DELETE
deletarUsuario(id: number): Observable<void> {
return this.http.delete<void>(`${this.baseUrl}/users/${id}`)
.pipe(catchError(this.handleError));
}
// Upload de arquivo
uploadArquivo(arquivo: File): Observable<any> {
const formData = new FormData();
formData.append('arquivo', arquivo);
return this.http.post(`${this.baseUrl}/upload`, formData)
.pipe(catchError(this.handleError));
}
// Tratamento de erros
private handleError(error: any) {
let errorMessage = 'Ocorreu um erro desconhecido';
if (error.error instanceof ErrorEvent) {
// Erro do lado do cliente
errorMessage = `Erro: ${error.error.message}`;
} else {
// Erro do lado do servidor
errorMessage = `Código: ${error.status}\nMensagem: ${error.message}`;
if (error.status === 401) {
// Não autorizado - redirecionar para login
window.location.href = '/login';
} else if (error.status === 404) {
errorMessage = 'Recurso não encontrado';
} else if (error.status === 500) {
errorMessage = 'Erro interno do servidor';
}
}
console.error(errorMessage);
return throwError(() => new Error(errorMessage));
}
}
🔌 HTTP Interceptors
// interceptors/auth.interceptor.ts
import { HttpInterceptorFn, HttpRequest, HttpHandlerFn, HttpEvent } from '@angular/common/http';
import { inject } from '@angular/core';
import { Observable } from 'rxjs';
export const authInterceptor: HttpInterceptorFn = (
req: HttpRequest<unknown>,
next: HttpHandlerFn
): Observable<HttpEvent<unknown>> => {
const token = localStorage.getItem('access_token');
if (token) {
const cloned = req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`)
});
return next(cloned);
}
return next(req);
};
// interceptors/logging.interceptor.ts
export const loggingInterceptor: HttpInterceptorFn = (req, next) => {
console.log(`📡 ${req.method} ${req.url}`);
const start = Date.now();
return next(req).pipe(
tap({
next: () => {
const duration = Date.now() - start;
console.log(`✅ ${req.method} ${req.url} - ${duration}ms`);
},
error: (error) => {
console.error(`❌ ${req.method} ${req.url}`, error);
}
})
);
};
Módulo 10: RxJS e Programação Reativa
📡 O que é RxJS?
RxJS (Reactive Extensions for JavaScript) é uma biblioteca para programação reativa usando Observables. Angular usa RxJS extensivamente para gerenciar operações assíncronas como requisições HTTP, eventos do usuário e estados reativos.
🔍 Observable vs Promise
- Promise: Retorna um único valor (ou erro)
- Observable: Pode emitir múltiplos valores ao longo do tempo
- Operadores: RxJS possui centenas de operadores para transformar dados
- Cancelamento: Observables podem ser cancelados (unsubscribe)
🔧 Operadores RxJS Essenciais
// ========== Criação de Observables ==========
import { Observable, of, from, interval, timer, Subject, BehaviorSubject } from 'rxjs';
import { map, filter, tap, debounceTime, switchMap, catchError, take, takeUntil } from 'rxjs/operators';
// Criar Observable com valores fixos
const numeros$ = of(1, 2, 3, 4, 5);
// Criar Observable a partir de array
const usuarios$ = from(['Ana', 'Pedro', 'Maria']);
// Criar Observable com intervalo
const intervalo$ = interval(1000); // Emite a cada 1 segundo
// Subject - Observable multicasting
const subject = new Subject<number>();
subject.subscribe(val => console.log('Sub1:', val));
subject.subscribe(val => console.log('Sub2:', val));
subject.next(1); // Todos recebem
// BehaviorSubject - mantém valor atual
const behaviorSubject = new BehaviorSubject<string>('inicial');
behaviorSubject.subscribe(val => console.log(val)); // Recebe 'inicial'
// ========== Operadores de Transformação ==========
numeros$.pipe(
map(x => x * 2), // Transforma: 1,2,3,4,5 → 2,4,6,8,10
filter(x => x > 5), // Filtra: 6,8,10
tap(x => console.log(x)), // Efeito colateral (debug)
take(2) // Pega apenas os 2 primeiros
).subscribe();
// ========== Exemplo Prático: Busca com debounce ==========
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged, switchMap, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
@Component({
template: `
<input [formControl]="buscaControl" placeholder="Buscar usuários...">
<ul>
<li *ngFor="let usuario of usuarios$ | async">{{ usuario.name }}</li>
</ul>
`
})
export class BuscaComponent {
buscaControl = new FormControl('');
usuarios$ = this.buscaControl.valueChanges.pipe(
debounceTime(300), // Aguarda 300ms sem digitar
distinctUntilChanged(), // Ignora valores repetidos
switchMap(termo => { // Cancela requisições anteriores
if (termo && termo.length >= 2) {
return this.apiService.buscarUsuarios(termo);
}
return of([]);
}),
catchError(error => {
console.error('Erro na busca:', error);
return of([]);
})
);
constructor(private apiService: ApiService) { }
}
🧹 Gerenciamento de Subscriptions
// ========== Método 1: Unsubscribe manual ==========
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
export class MeuComponente implements OnInit, OnDestroy {
private subscriptions = new Subscription();
ngOnInit() {
const sub1 = this.apiService.getDados().subscribe();
const sub2 = this.outroService.getDados().subscribe();
this.subscriptions.add(sub1);
this.subscriptions.add(sub2);
}
ngOnDestroy() {
this.subscriptions.unsubscribe(); // Cancela todas subscriptions
}
}
// ========== Método 2: Async Pipe (recomendado) ==========
// O async pipe cancela automaticamente a subscription
@Component({
template: `
<div *ngIf="dados$ | async as dados">
{{ dados | json }}
</div>
`
})
export class MeuComponente {
dados$ = this.apiService.getDados();
constructor(private apiService: ApiService) { }
}
// ========== Método 3: takeUntil (padrão comum) ==========
import { Subject, takeUntil } from 'rxjs';
export class MeuComponente implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
ngOnInit() {
this.apiService.getDados()
.pipe(takeUntil(this.destroy$))
.subscribe();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
Módulo 11: Pipes e Transformação de Dados
🔧 Pipes Built-in
DatePipe
{{ data | date:'dd/MM/yyyy' }}
{{ data | date:'fullDate' }}
{{ data | date:'shortTime' }}
CurrencyPipe
{{ valor | currency:'BRL' }}
{{ valor | currency:'USD':'symbol' }}
{{ valor | currency:'EUR':'code' }}
DecimalPipe
{{ numero | number:'1.2-2' }}
{{ pi | number:'1.2-5' }}
PercentPipe
{{ 0.25 | percent }}
{{ 0.1234 | percent:'1.2-2' }}
UpperCasePipe / LowerCasePipe
{{ texto | uppercase }}
{{ texto | lowercase }}
JsonPipe
{{ objeto | json }}
🛠️ Criando Pipes Customizados
// gerar pipe: ng g pipe truncate
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate',
standalone: true
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit: number = 50, ellipsis: string = '...'): string {
if (!value) return '';
if (value.length <= limit) return value;
return value.substring(0, limit) + ellipsis;
}
}
// gerar pipe: ng g pipe filter
@Pipe({
name: 'filter',
standalone: true
})
export class FilterPipe implements PipeTransform {
transform<T>(items: T[], searchTerm: string, key: keyof T): T[] {
if (!items || !searchTerm) return items;
searchTerm = searchTerm.toLowerCase();
return items.filter(item => {
const value = item[key] as string;
return value && value.toLowerCase().includes(searchTerm);
});
}
}
// gerar pipe: ng g pipe safeHtml
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Pipe({
name: 'safeHtml',
standalone: true
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) { }
transform(value: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
// Uso no template
<p>{{ textoLongo | truncate:100:'...' }}</p>
<ul>
<li *ngFor="let usuario of usuarios | filter:termo:'nome'">
{{ usuario.nome }}
</li>
</ul>
<div [innerHTML]="htmlContent | safeHtml"></div>
Módulo 12: Testes Unitários e E2E
🧪 Testes Unitários com Jasmine e Karma
// meu-componente.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MeuComponenteComponent } from './meu-componente.component';
import { FormsModule } from '@angular/forms';
describe('MeuComponenteComponent', () => {
let component: MeuComponenteComponent;
let fixture: ComponentFixture<MeuComponenteComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [FormsModule, MeuComponenteComponent]
}).compileComponents();
fixture = TestBed.createComponent(MeuComponenteComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('deve criar o componente', () => {
expect(component).toBeTruthy();
});
it('deve ter título inicial "Meu Componente"', () => {
expect(component.titulo).toBe('Meu Componente');
});
it('deve incrementar contador ao chamar incrementar()', () => {
component.contador = 5;
component.incrementar();
expect(component.contador).toBe(6);
});
it('deve decrementar contador ao chamar decrementar()', () => {
component.contador = 5;
component.decrementar();
expect(component.contador).toBe(4);
});
it('deve exibir o valor do contador no template', () => {
component.contador = 10;
fixture.detectChanges();
const elemento = fixture.debugElement.query(By.css('.contador-valor'));
expect(elemento.nativeElement.textContent).toContain('10');
});
it('deve emitir evento quando contador mudar', () => {
spyOn(component.contadorAlterado, 'emit');
component.incrementar();
expect(component.contadorAlterado.emit).toHaveBeenCalledWith(1);
});
});
🧪 Testes de Serviço com HttpClientTestingModule
// api.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { ApiService, Usuario } from './api.service';
describe('ApiService', () => {
let service: ApiService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ApiService]
});
service = TestBed.inject(ApiService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpMock.verify(); // Verifica se não há requisições pendentes
});
it('deve ser criado', () => {
expect(service).toBeTruthy();
});
it('deve buscar usuários via GET', () => {
const usuariosMock: Usuario[] = [
{ id: 1, name: 'João', email: 'joao@email.com', username: 'joao' },
{ id: 2, name: 'Maria', email: 'maria@email.com', username: 'maria' }
];
service.getUsuarios().subscribe(usuarios => {
expect(usuarios).toEqual(usuariosMock);
expect(usuarios.length).toBe(2);
});
const req = httpMock.expectOne('https://jsonplaceholder.typicode.com/users');
expect(req.request.method).toBe('GET');
req.flush(usuariosMock);
});
it('deve tratar erro 404', () => {
service.getUsuario(999).subscribe({
error: (error) => {
expect(error.message).toContain('404');
}
});
const req = httpMock.expectOne('https://jsonplaceholder.typicode.com/users/999');
req.flush('Not Found', { status: 404, statusText: 'Not Found' });
});
});
Módulo 13: Build e Deploy
🚀 Build para Produção
# Build padrão
ng build
# Build otimizado para produção
ng build --prod
# ou
ng build --configuration production
# Build com análise de tamanho
ng build --stats-json
# Build com source maps (para debug)
ng build --source-map
# Build para ambiente específico
ng build --configuration staging
⚙️ Configuração de Environments
// src/environments/environment.ts (desenvolvimento)
export const environment = {
production: false,
apiUrl: 'http://localhost:3000/api',
appName: 'App Dev'
};
// src/environments/environment.prod.ts (produção)
export const environment = {
production: true,
apiUrl: 'https://api.minhaapp.com',
appName: 'Minha App'
};
// Uso no código
import { environment } from '../environments/environment';
export class ApiService {
private apiUrl = environment.apiUrl;
}
🚀 Deploy em Diferentes Plataformas
📦 GitHub Pages
npm install -g angular-cli-ghpages
ng build --prod --base-href "https://usuario.github.io/repo/"
npx angular-cli-ghpages --dir=dist/nome-projeto
☁️ Vercel
npm i -g vercel
vercel
# Selecionar pasta dist/nome-projeto
🔥 Firebase Hosting
npm install -g firebase-tools
firebase login
firebase init hosting
ng build --prod
firebase deploy
🐳 Docker
# Dockerfile
FROM nginx:alpine
COPY dist/nome-projeto /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
35+ Exercícios Práticos
1. Configuração de Ambiente
Instale Node.js, Angular CLI e crie seu primeiro projeto. Verifique se o servidor roda em http://localhost:4200
2. Meu Primeiro Componente
Crie um componente que exiba seu nome, idade e uma mensagem de boas-vindas usando interpolação.
3. Contador Interativo
Crie um componente com botões + e -, que atualize um contador. Adicione limite mínimo de 0 e máximo de 100.
4. Lista de Tarefas (To-Do List)
Desenvolva uma aplicação para adicionar, marcar como concluída e remover tarefas. Use *ngFor e *ngIf.
5. Formulário de Cadastro
Crie um formulário reativo com nome, email, senha e confirmação de senha com validações personalizadas.
6. Consumindo API
Consuma a API JSONPlaceholder, exiba os usuários em uma tabela e adicione um campo de busca.
7. Roteamento
Crie um site com 4 páginas (Home, Sobre, Produtos, Contato) usando Angular Router com navegação.
8. Filtro com Pipes
Crie um pipe customizado para filtrar uma lista de produtos por nome e categoria.
9. Serviço com Estado Global
Crie um serviço com BehaviorSubject para gerenciar o estado de autenticação do usuário.
10. Guarda de Rotas
Implemente um AuthGuard que protege rotas administrativas e redireciona para login se não autenticado.
11. HTTP Interceptor
Crie um interceptor que adiciona token JWT a todas as requisições e trata erros 401.
12. Upload de Arquivos
Crie um componente que permite upload de imagens com preview e validação de tamanho/tipo.
13. Formulário Dinâmico
Crie um formulário que permite adicionar/remover campos dinamicamente usando FormArray.
14. Testes Unitários
Escreva testes para um componente, um serviço e um pipe usando Jasmine.
15. Deploy (Projeto Final)
Faça o build do projeto e faça deploy no Firebase, Vercel ou GitHub Pages.
Glossário Técnico
🅰️ Angular CLI
Ferramenta de linha de comando para criar, gerenciar e fazer build de projetos Angular.
🧩 Componente
Bloco fundamental do Angular que controla uma parte da interface (template + lógica).
🔌 Serviço
Classe que contém lógica de negócio, compartilhada entre componentes via injeção de dependência.
📡 Observable
Objeto do RxJS que emite valores ao longo do tempo, usado para programação assíncrona.
🛣️ Router
Módulo do Angular que gerencia navegação entre componentes/páginas.
🔧 Diretiva
Classe que adiciona comportamento a elementos no DOM.
🔧 Pipe
Função que transforma dados diretamente no template.
💉 DI (Injeção de Dependência)
Padrão de design onde as dependências são fornecidas ao invés de criadas internamente.
🧪 TestBed
Classe utilitária para configurar testes unitários no Angular.
🚀 Lazy Loading
Técnica de carregar módulos sob demanda, melhorando performance inicial.
📋 Resumo do Treinamento
✅ O que você aprendeu:
- Configurar ambiente Angular em Windows, Mac e Linux
- Fundamentos TypeScript aplicados ao Angular
- Criar e gerenciar componentes reutilizáveis
- Usar diretivas estruturais e de atributo
- Criar serviços e entender injeção de dependência
- Implementar roteamento com guards e lazy loading
- Construir formulários reativos e template-driven
- Consumir APIs REST com HttpClient e interceptors
- Programação reativa com RxJS (Observables, operadores)
- Criar pipes customizados e usar pipes built-in
- Escrever testes unitários com Jasmine
- Fazer build e deploy para produção
- 35+ exercícios práticos para fixação
📊 Seu Progresso:
Treinamento Completo ✓ | Mais de 2.500 linhas de conteúdo
Comentários 0
Deixe seu comentário
Faça login para comentar sem moderação. Comentários de usuários não logados precisam de aprovação.