Por que o simples document.querySelector não funciona no Angular?
\n\nImagine: você está escrevendo seu primeiro aplicativo Angular e precisa acessar um simples <div> ou <input> diretamente no template do componente. O primeiro pensamento é usar o bom e velho document.querySelector. Mas eis o problema: no console — null ou undefined. Familiar?
Angular não é apenas uma biblioteca para manipulação do DOM. É um framework que trabalha com sua própria abstração sobre o DOM real. O acesso direto aos elementos através de seletores globais viola a arquitetura do framework, pode causar vazamentos de memória e problemas de desempenho. Mas a principal razão é que o Angular usa DOM virtual e Shadow DOM (dependendo da estratégia de encapsulamento), então seu document.querySelector simplesmente não vê os elementos dentro do componente.
Felizmente, os desenvolvedores do Angular forneceram uma solução elegante — os decoradores ViewChild e ViewChildren. Neste artigo, vamos explorar como selecionar corretamente elementos no template do componente usando TypeScript e abordar todas as armadilhas.
\n\nPrincipais formas de acessar elementos do template
\n\nNo Angular, existem três abordagens principais para selecionar elementos no template do componente:
\n\n- \n
- Referências de Template (Template Reference Variables) — a maneira mais simples para acesso rápido \n
- Decorador ViewChild — para acessar um único elemento ou componente \n
- Decorador ViewChildren — para acessar uma coleção de elementos do mesmo tipo \n
Cada uma dessas abordagens tem suas particularidades e é aplicada em diferentes cenários. Vamos analisá-las em detalhes.
\n\n1. Referências de Template: a maneira mais rápida
\n\nAs referências de template são um "truque" do Angular que permite acessar um elemento DOM diretamente no template, sem precisar escrever código na classe do componente. Basta colocar #nomeDaReferencia no elemento desejado.
// component.html\n<input #myInput type="text" placeholder="Digite o texto">\n<button (click)="focusInput(myInput)">Focar no input</button>\n\nNeste exemplo, #myInput é uma referência de template. Ela cria automaticamente uma variável que pode ser passada para os métodos do componente. Observe: estamos passando o próprio elemento, não seu valor.
// component.ts\nimport { Component } from '@angular/core';\n\n@Component({\n selector: 'app-example',\n templateUrl: './example.component.html'\n})\nexport class ExampleComponent {\n focusInput(inputElement: HTMLInputElement): void {\n inputElement.focus();\n inputElement.style.borderColor = '#4CAF50';\n }\n}\n\nPonto importante: as referências de template estão disponíveis apenas dentro do template. Você não pode usá-las diretamente na classe do componente. Para isso, são necessários os decoradores.
\n\n2. ViewChild: acesso a um único elemento
\n\nO decorador @ViewChild é a ferramenta principal para obter acesso a um elemento ou componente filho a partir da classe do componente. Ele funciona com base em um seletor: você pode pesquisar por referência de template, por tipo de componente ou por seletor CSS (com limitações).
// component.ts\nimport { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';\n\n@Component({\n selector: 'app-example',\n template: `\n <div #myDiv>Este elemento vamos selecionar</div>\n <p #myParagraph>E este também</p>\n `\n})\nexport class ExampleComponent implements AfterViewInit {\n @ViewChild('myDiv') myDiv!: ElementRef;\n @ViewChild('myParagraph') myParagraph!: ElementRef;\n\n ngAfterViewInit(): void {\n // Importante! O acesso aos elementos só é possível após a inicialização da view\n console.log(this.myDiv.nativeElement.textContent); // "Este elemento vamos selecionar"\n this.myPara