Pular para conteúdo

Angular

Angular é um framework do Google para construir aplicações web de página única (SPAs) — e, com ferramentas ligadas a ele, aplicativos móveis e desktop — usando HTML, CSS e TypeScript. Compete com React e Vue em vagas de front-end.

Sobre as versões

As fontes cobrem o Angular 2/4 (2016–2017) e o Angular 11 (2021). Os conceitos centrais (componentes, templates, data binding, injeção de dependência, módulos, rotas, formulários, serviços e RxJS) continuam válidos; o que mudou está em O que mudou nas versões recentes. Os trechos marcados como complemento não estão nos livros.

O que é e por que SPA

Definição: SPA (Single Page Application)

Aplicação que carrega uma única página e, a partir daí, troca partes do HTML (templates) no próprio navegador. O servidor só devolve dados brutos (JSON); não há recarregamento da página inteira.

Vantagem de uma SPA Por quê
Experiência Parece uma aplicação desktop: só trechos da tela mudam
Desempenho Transições entre telas não precisam ser montadas e enviadas pelo servidor; tráfego menor
Carga no servidor Ele só recebe a requisição, processa e devolve JSON

Complemento — contrapartida: SEO e primeiro carregamento exigem cuidado (renderização no servidor/SSR, pré-renderização).

Angular x AngularJS: o Angular 2+ não é continuação do AngularJS (1.x): foi reescrito do zero, mais rápido (menos interações com o DOM), baseado em componentes e TypeScript. Desde o Angular 2 há um ciclo de lançamentos a cada ~6 meses com versionamento semântico; a equipe pede que se diga apenas "Angular" (e não "Angular 2/3/4…"), para evitar a impressão de que cada versão é um framework novo. Atualizar entre versões costuma ser só trocar os pacotes (ng update hoje).

Pré-requisitos: ES6 e TypeScript

ECMAScript (JavaScript moderno)

ECMAScript (ES) é a especificação do JavaScript; desde 2015 (ES6/ES2015) há uma edição por ano. Recursos que aparecem o tempo todo no Angular:

let nome = 'Angular';            // let: escopo de BLOCO (var tem escopo de função/global)
const PI = 3.14;                 // const: não pode ser reatribuída

function somar(x: number, y = 1) { return x + y; }     // parâmetro padrão (default parameter)
const somar2 = (x: number, y = 1) => x + y;            // arrow function

const [a, b] = [1, 2];                                  // destructuring de array
const { livro, autor } = { livro: 'Angular', autor: 'X' };   // destructuring de objeto

[2, 3, 4].map(n => n * 2);                // [4, 6, 8]  transforma cada elemento
['jorge', 'carlos'].filter(n => n.includes('a'));       // ['carlos']  mantém os que passam no teste
[1, 2, 3].reduce((acc, n) => acc + n, 0); // 6          reduz a um único valor

TypeScript

Definição: TypeScript

Superset de JavaScript da Microsoft com tipagem estática e sintaxe de classes parecida com Java/C#. É compilado (transpilado) para JavaScript, porque os navegadores não o executam; o tsconfig.json define o alvo de compilação. Os polyfills garantem recursos modernos em navegadores antigos.

class Pessoa {
  private nome: string;                       // visibilidade: public (padrão), private, protected
  constructor(nome: string, public idade?: number) { this.nome = nome; }   // ? = opcional

  saudar(): string { return `Olá, ${this.nome}`; }
  logar(msg: string | number): void { console.log(msg); }   // união de tipos; void = sem retorno
}

function qualquer(x: any) { }                 // any desliga a checagem de tipos: evite
interface ICrud<T> { get(id: string): Observable<T>; }       // interfaces e genéricos

Ambiente e Angular CLI

O ambiente usa Node.js (executa JavaScript fora do navegador) e o npm (gerenciador de pacotes, package.json), e o Angular CLI (ng) para criar, gerar artefatos, testar e construir.

npm install -g @angular/cli
ng new minha-app                # cria o projeto
ng serve -o                     # servidor de desenvolvimento em localhost:4200 (recarrega ao salvar)
ng generate component lista-pessoa     # ng g c  — cria .ts, .html, .css e .spec.ts
ng g service alerta                    # ng g s
ng g module admin --routing            # ng g m
ng test                                # testes unitários (Karma + Jasmine)
ng lint                                # boas práticas do guia de estilo
ng build                               # gera a pasta dist/ para produção (no passado: ng build --prod)

Estrutura do projeto: src/app (todo o código da aplicação), app.module.ts (módulo raiz), main.ts (bootstrap), index.html (a única página), environments/ (configurações por ambiente: environment.ts e environment.prod.ts), angular.json (configuração do projeto), package.json (dependencies para produção e devDependencies só para desenvolvimento), node_modules.

Como a aplicação inicia: index.html carrega → main.ts chama platformBrowserDynamic().bootstrapModule(AppModule) → o AppModule declara os objetos e indica, em bootstrap, o componente raiz (AppComponent) → o Angular lê o @Component, renderiza o template e mostra a aplicação. (O bootstrap do Angular não tem relação com o framework CSS Bootstrap.)

Arquitetura: as peças de uma aplicação

flowchart LR
    M["NgModule<br/>(declarations, imports, providers, bootstrap)"] --> C["Componente<br/>(classe + template + metadata)"]
    C <-->|"data binding"| T["Template (HTML)"]
    C -->|"injeção de dependência"| S["Serviços (@Injectable)"]
    D["Diretivas e pipes"] --> T
    S --> API[("API / Firebase")]
    R["Roteador"] --> C

Componente, template e metadata

Definição: Componente

A unidade central do Angular: uma classe TypeScript que controla uma view + um template HTML + metadados do decorador @Component. Em Angular "tudo é componente"; uma página é a composição de componentes pequenos, cada um com uma responsabilidade (modularização: mais fácil de construir, testar e reutilizar).

@Component({
  selector: 'app-lista-pessoa',                  // como a tag aparece em outro template
  templateUrl: './lista-pessoa.component.html',  // (ou template: inline)
  styleUrls: ['./lista-pessoa.component.css'],   // estilos do componente
  providers: [PessoaService]                     // serviços visíveis só aqui (opcional)
})
export class ListaPessoaComponent implements OnInit {
  pessoas: string[] = [];
  constructor(private service: PessoaService) { }   // injeção de dependência

  ngOnInit() { this.pessoas = this.service.getPessoas(); }   // gancho de ciclo de vida
}
  • A classe contém só a lógica de controle da view: regras de negócio, validações e acesso a dados vão para serviços.
  • Um decorador (@Component, @NgModule, @Injectable, @Input...) anexa metadados à classe, ao método ou à propriedade.
  • Ciclo de vida: ngOnInit() (depois de definir as propriedades de entrada — o lugar de inicializar e chamar serviços), ngOnChanges, ngOnDestroy (limpeza, cancelar subscriptions).
  • O construtor é para declarar dependências e inicializações simples.

Data binding: quatro formas de ligar classe e template

Forma Sintaxe Direção Exemplo
Interpolação {{ valor }} classe → template <h1>{{ titulo }}</h1>
Property binding [propriedade]="expr" classe → propriedade da tag <img [src]="foto">
Event binding (evento)="acao()" template → classe <button (click)="salvar()">
Two-way binding [(ngModel)]="variavel" ambas (combina as duas anteriores, "banana na caixa") <input [(ngModel)]="nome">

Eventos úteis: (click), (keyup), (keyup.enter), (blur), (ngSubmit). Variável de referência do template (#campo) dá acesso a um elemento ou ao ngModel dentro do próprio template.

Diretivas

Diretivas modificam o DOM. Os próprios componentes são um tipo de diretiva.

Tipo O que faz Exemplos
Estruturais (prefixo *) Adicionam/removem elementos do DOM *ngIf, *ngFor, ngSwitch
De atributo Mudam aparência/comportamento sem alterar a estrutura [ngClass], [ngStyle], [(ngModel)]
<li *ngFor="let pessoa of pessoas; let i = index">{{ i + 1 }} - {{ pessoa }}</li>

<div *ngIf="logado; else visitante">Bem-vindo!</div>        <!-- else existe desde o Angular 4 -->
<ng-template #visitante><p>Faça login</p></ng-template>

<span [ngClass]="{ ativo: ok, erro: !ok }" [ngStyle]="{ 'font-size.px': tamanho }">...</span>
<ng-content></ng-content>   <!-- "projeção" de conteúdo: o que o pai coloca entre as tags do componente -->
  • No ngFor, index as i e count as total expõem posição e quantidade; trackBy (complemento) evita recriar todos os elementos ao mudar a lista.
  • Variáveis de template com async (dados$ | async) assinam um Observable sem código manual.

Serviços e injeção de dependência

Definição: Serviço e injeção de dependência (DI)

Serviço é uma classe @Injectable() com lógica que não pertence a um componente: regras de negócio, validação, log, tratamento de erros, acesso a servidor/banco — o que também permite reaproveitar e testar. Injeção de dependência: o componente declara no construtor o que precisa e o Angular fornece a instância, gerenciada por um contêiner (reutilizando a que já existe), em vez de usar new.

@Injectable({ providedIn: 'root' })        // instância única na aplicação (Angular 6+)
export class AlertaService {
  msgAlerta(): void { alert('Olá'); }
}

constructor(private alerta: AlertaService) { }      // o Angular injeta
  • Sem provider registrado: No provider for AlertaService! — o serviço precisa ser fornecido (providedIn: 'root', providers do módulo ou do componente).
  • Regra de escopo: declarado em providers do componente → instância própria, só dele; declarado no módulo/raiz → instância compartilhada por todos. Serviço usado por mais de um componente deve ser global.
  • Instanciar manualmente (new Servico()) é má prática: perde-se o gerenciamento e podem surgir várias instâncias.
  • O guia de estilo recomenda classes de até ~400 linhas e métodos de até ~75.
  • Dependências podem ser opcionais (@Optional()), e serviços podem injetar outros serviços.
  • Relação com o padrão em Dependency Injection e com o Spring.

NgModule

Módulos reúnem componentes, diretivas, pipes e serviços de mesma finalidade; toda aplicação tem ao menos o AppModule. Campos do @NgModule:

Campo Para quê
declarations Componentes, diretivas e pipes que pertencem a este módulo (se não for declarado, o Angular não o reconhece)
imports Outros módulos usados (BrowserModule, FormsModule, HttpClientModule, módulos de bibliotecas)
providers Serviços disponíveis para a injeção
exports O que o módulo disponibiliza a quem o importar (módulos compartilhados)
bootstrap Componente raiz (só no módulo raiz)

Convenção de organização dos imports no arquivo: primeiro os do Angular, depois os de terceiros e por último os do próprio projeto, separados por linha em branco. Sempre dois passos: importar o símbolo e declará-lo no @NgModule apropriado.

Comunicação entre componentes

  • @Input(): o pai passa dados ao filho — @Input() menu: string; no filho e <app-filho [menu]="lista"></app-filho> no pai.
  • @Output() + EventEmitter: o filho avisa o pai — o filho emite o evento e o pai o trata.
  • Outras formas: serviços compartilhados (com Observables), roteador, projeção (ng-content).

// filho
@Input() menu!: string[];
@Output() nomeClicado = new EventEmitter<string>();
enviar(item: string) { this.nomeClicado.emit(item); }
<!-- pai -->
<app-filho [menu]="itens" (nomeClicado)="mostrar($event)"></app-filho>

Formulários

O Angular tem duas abordagens:

Template-driven (orientado a template) Reativos (reactive forms)
Quando Formulário simples (ex.: login) Formulários complexos, reutilizáveis e escaláveis
Módulo FormsModule ReactiveFormsModule
Como ngModel, validações por atributos HTML FormGroup/FormControl criados na classe, [formGroup] e formControlName no template
Validação required, minlength, maxlength, email; #campo="ngModel" expõe valid, errors, pristine, touched Validators.required, Validators.email, vários em lista; validadores próprios
<!-- template-driven -->
<form #cadastro="ngForm" (ngSubmit)="enviar()">
  <input name="email" [(ngModel)]="email" #emailCtl="ngModel" required email>
  <div *ngIf="emailCtl.invalid && emailCtl.touched">
    <small *ngIf="emailCtl.errors?.['required']">Email obrigatório</small>
    <small *ngIf="emailCtl.errors?.['email']">Email inválido</small>
  </div>
  <button type="submit" [disabled]="cadastro.form.invalid">Enviar</button>
</form>

// reativo
this.form = this.fb.group({
  nome: new FormControl('', Validators.required),
  email: new FormControl('', [Validators.required, Validators.email]),
});
ngModelGroup agrupa campos. Prefira o reativo quando houver regras, campos dinâmicos ou testes.

Rotas, guardas e lazy loading

O roteador associa URLs a componentes; o componente do <router-outlet> marca onde a tela roteada aparece; routerLink cria links e routerLinkActive marca o ativo; Router.navigate([...]) navega por código.

const routes: Routes = [
  { path: '', redirectTo: 'login', pathMatch: 'full' },
  { path: 'login', component: LoginComponent },
  { path: 'admin/painel',
    loadChildren: () => import('./painel/painel.module').then(m => m.PainelModule),   // lazy loading
    canActivate: [AuthGuard] },                                                        // guarda de rota
];
  • Lazy loading: dividir a aplicação em módulos carregados só quando o usuário navega para a rota, reduzindo o tempo de carga inicial (usa a importação dinâmica import()).
  • Guardas (CanActivate e similares) decidem se uma rota pode ser ativada; por exemplo, redirecionar para o login se não houver usuário autenticado:

canActivate(): Observable<boolean> {
  return this.afAuth.authState.pipe(
    take(1), map(user => !!user),
    tap(logado => { if (!logado) this.router.navigate(['/login']); }));
}
- Módulos compartilhados (CommonModule, FormsModule, módulos de biblioteca de componentes exportados em um único módulo) evitam repetir importações. Guardas protegem a navegação, mas a segurança real está no servidor (regras do banco, autorização na API).

Pipes e RxJS

  • Pipe transforma um valor para exibição: {{ valor | date }}, uppercase, currency, async. Pode-se criar um próprio com @Pipe({ name: 'filtro' }) implementando PipeTransform.transform() (ex.: filtrar uma lista por departamento).
  • Observable (RxJS): fluxo de dados assíncronos que pode emitir vários valores no tempo; é a base de HttpClient, do roteador e dos formulários. Promise representa um resultado futuro. subscribe() (ou o pipe async) assina o fluxo; operadores como map, take, tap e filter se combinam em .pipe(...). Cancele as assinaturas manuais em ngOnDestroy.

Firebase: back-end como serviço

Firebase é a plataforma de serviços do Google para aplicações: o Angular cuida da interface e o Firebase da infraestrutura (escalável e com plano gratuito). Biblioteca oficial: AngularFire.

Serviço Para quê
Authentication Login pronto (e-mail/senha, Google, Facebook...): signInWithEmailAndPassword, signOut, sendPasswordResetEmail; authState é um Observable do usuário
Cloud Firestore Banco NoSQL de documentos (coleções → documentos), com sincronização e consultas em escala (NoSQL)
Cloud Storage Armazenamento de arquivos (fotos, anexos); upload devolve o progresso como Observable e a URL de download
Cloud Functions Funções no servidor disparadas por eventos (ex.: criar o usuário de autenticação quando um documento é criado; enviar e-mail quando uma requisição é atualizada); implantadas com a firebase-tools (firebase deploy)
Hosting Hospedagem do SPA com HTTPS, histórico de versões e rollback (firebase init hosting, firebase deploy --only hosting)
  • Regras de segurança (Security Rules) controlam quem lê e grava: modo bloqueado (nega tudo) ou teste (libera tudo — nunca em produção). Exemplo: permitir só usuários autenticados (allow read, write: if request.auth != null;), com regras por coleção/operação.
  • A configuração do Firebase para a web (chaves no environment.ts) identifica o projeto, mas não é segredo de acesso: quem protege os dados são as regras de segurança. Já segredos de servidor (chaves de contas de serviço, .env com senhas) jamais vão ao repositório.
  • O Firebase só aceita objetos literais (JSON simples): modelos TypeScript com métodos precisam ser convertidos (a fonte usa a biblioteca class-transformer, classToPlain/plainToClass).
  • Lock-in: o Firestore e as functions prendem a aplicação ao Google (Nuvem: lock-in).

Padrão: serviço genérico de CRUD

Para não repetir código nem misturar acesso a dados nos componentes (o que o guia de estilo desaconselha), define-se uma interface genérica e uma classe base abstrata que as entidades herdam:

export interface ICrud<T> {
  get(id: string): Observable<T>;
  list(): Observable<T[]>;
  createOrUpdate(item: T): Promise<T>;
  delete(id: string): Promise<void>;
}

export abstract class ServiceFirebase<T extends Model> implements ICrud<T> {
  protected ref: AngularFirestoreCollection<T>;
  constructor(protected type: { new(): T }, protected firestore: AngularFirestore, public path: string) {
    this.ref = this.firestore.collection<T>(this.path);
  }
  // get / list / createOrUpdate / delete implementados uma única vez (valueChanges() devolve um Observable)
}

@Injectable({ providedIn: 'root' })
export class DepartamentoService extends ServiceFirebase<Departamento> {
  constructor(firestore: AngularFirestore) { super(Departamento, firestore, 'departamentos'); }
}

Mesmo princípio dos padrões Repository/DAO (Acesso a dados) e das classes abstratas/genéricos de OO: o que varia (entidade e coleção) vai no construtor; o comportamento comum fica na base. Convenção: coleção com o nome da entidade no plural.

Testes, build e deploy

  • Unitários: Karma + Jasmine (arquivos .spec.ts, um por componente/serviço). Integração/e2e: Protractor na época (hoje descontinuado: Cypress, Playwright). Pirâmide em Qualidade.
  • Build: ng build gera a pasta dist/ otimizada (minificação e tree shaking) e AOT (Ahead of Time: converte HTML e TypeScript em JavaScript eficiente antes do navegador baixá-lo, com renderização mais rápida). Na versão 4 o código gerado diminuiu até 60%.
  • Ivy (padrão desde o Angular 9): reescrita do compilador e do runtime — compilação incremental, bundles menores, carregamento preguiçoso de componentes. Não muda como se escreve o código.
  • Variáveis por ambiente em environments/; esteira de CI/CD em CI/CD.

O que mudou nas versões recentes

Complemento (o que o código dos livros faria diferente hoje):

Livro (Angular 2–11) Angular atual (17+)
NgModule obrigatório Componentes standalone (standalone: true, imports: [...] no próprio componente)
*ngIf, *ngFor, *ngSwitch Controle de fluxo nativo: @if (...) {...} @else {...}, @for (item of lista; track item.id), @switch
Injeção só por construtor Função inject() também (private http = inject(HttpClient))
HttpModule / Http (Angular 2) HttpClient (provideHttpClient()), respostas tipadas e interceptors
Detecção de mudanças com zone.js Signals (signal(), computed(), effect()) para estado reativo com detecção mais fina
TSLint, Protractor, Webpack ESLint, Cypress/Playwright, builder baseado em esbuild/Vite
ng build --prod ng build já é de produção por padrão
AngularFire 6 (API namespaced) AngularFire modular (7+), com funções em vez de classes

AngularJS (1.x): o legado

O AngularJS (2010–2021, fim do suporte) foi o framework MVC do Google que popularizou as SPAs e o data binding. Muitos sistemas ainda o usam, e em entrevistas ele aparece como termo de comparação. Dá para entender o Angular moderno como a resposta aos seus problemas de desempenho e escala.

Definição: AngularJS

Framework JavaScript que estende o HTML com diretivas e expressões: o desenvolvedor escreve o template HTML e o AngularJS mantém a página sincronizada com o modelo ($scope) por data binding bidirecional, sem manipular o DOM manualmente.

Conceito (AngularJS 1.x) O que faz Equivalente no Angular moderno
Módulo (angular.module) e ng-app Agrupa e inicializa a aplicação NgModule / standalone components
Controller + $scope Expõe dados e ações para a view Componente (classe)
Expressão {{ nome }} Interpola dados no HTML Interpolação {{ }}
Diretivas ng-repeat, ng-model, ng-click, ng-if, ng-class Estendem o HTML *ngFor/@for, [(ngModel)], (click), *ngIf/@if, [ngClass]
Data binding bidirecional Alterou no campo, muda o modelo e vice-versa (via digest cycle, custoso em listas grandes) Binding unidirecional por padrão, com detecção de mudanças por componente (e signals)
Serviços/factories ($http, $resource) Lógica reutilizável e acesso a APIs, com injeção de dependência Serviços @Injectable + HttpClient
Rotas ngRoute ($routeProvider, $routeParams) Navegação da SPA @angular/router
Filtros (| currency) Formatam valores no template Pipes
Diretivas próprias Componentes de UI reutilizáveis Componentes e diretivas
Promises ($q) Resultado assíncrono Observable (RxJS) e async/await

Pontos que costumam ser perguntados:

  • Injeção de dependência por nome: o AngularJS descobre as dependências pelo nome dos parâmetros da função, o que quebra na minificação (os nomes são encurtados). A solução é a anotação em array (['$scope', '$http', function($scope, $http){...}]) ou ng-annotate. O Angular moderno usa types e o compilador.
  • Digest cycle: a cada evento o AngularJS percorre todas as watches até o modelo estabilizar — por isso muitas ligações deixam a página lenta.
  • Por que migrar: fim do suporte, desempenho, TypeScript, componentes e ferramentas modernas (CLI, AOT). A migração costuma ser incremental (ngUpgrade) ou por reescrita.
  • Testes: Karma + Jasmine, com angular-mocks e $httpBackend para simular o back-end; testes de ponta a ponta com Protractor (hoje descontinuado, substituído por Playwright/Cypress).

Em conjunto com Node, Express e MongoDB, formou a MEAN Stack (Node.js e Express).

Perguntas comuns de entrevista (resumo)

Pergunta Resposta curta
O que é uma SPA? Aplicação que carrega uma página e troca templates no navegador, buscando só dados (JSON) no servidor
Angular x AngularJS? O Angular 2+ foi reescrito do zero, com componentes, TypeScript e melhor desempenho; não é continuação do AngularJS
O que é um componente? Classe decorada com @Component + template + estilos; unidade de UI reutilizável
Quais os tipos de data binding? Interpolação, property, event e two-way ([(ngModel)])
Diretiva estrutural x de atributo? Estrutural muda a estrutura do DOM (*ngIf, *ngFor); de atributo muda aparência/comportamento (ngClass, ngStyle)
O que é injeção de dependência no Angular? O componente declara no construtor o que precisa e o Angular fornece instâncias gerenciadas dos serviços
Onde declarar um serviço? providedIn: 'root'/módulo para compartilhar; providers do componente para instância própria
@Input x @Output? @Input: pai → filho; @Output + EventEmitter: filho → pai
Template-driven x reactive forms? Template-driven é simples, baseado em ngModel; reativos criam o modelo na classe, são mais testáveis e escaláveis
O que é lazy loading? Carregar um módulo só quando a rota for acessada, reduzindo o carregamento inicial
Observable x Promise? O Observable pode emitir vários valores e ser cancelado; a Promise resolve uma única vez
O que é AOT? Compilação do Angular antes de o navegador receber o código, com renderização mais rápida