Atualizado: 03/01/2025

Variáveis de Template e ViewChild - Angular

As variáveis de template permitem definir algumas variáveis dentro do template de um componente e, em seguida, referenciar essas variáveis dentro do mesmo template. Para definir essas variáveis, utiliza-se o símbolo de cerquilha (#). Por exemplo, vamos definir uma variável de template chamada userName em um componente:

import { Component } from "@angular/core";
import { FormsModule } from "@angular/forms";

@Component({
    selector: "my-app",
    standalone: true,
    imports: [FormsModule],
    template: `
                <p #userName>{{name}}</p>
                <p>{{userName.textContent}}</p>
                <input type="text" [(ngModel)]="name" />`
})
export class AppComponent { 
    name = "Tom";
}

A definição de template tem a seguinte estrutura:

<p #userName>{{name}}</p>

A definição da variável userName no elemento <p> indica que ela representará este parágrafo, ou seja, o elemento <p> na marcação HTML. Posteriormente, podemos referenciar este parágrafo por meio da variável. Por exemplo, usando a propriedade userName.textContent, podemos obter o conteúdo textual do parágrafo. Se o valor da variável name, que está vinculado ao parágrafo, for alterado, o valor de userName.textContent será atualizado automaticamente:

Variáveis de Template em Angular

Interação entre Componentes Pai e Filho

O uso de variáveis de template oferece uma maneira adicional de interação entre o componente pai e o componente filho. Por exemplo, vamos definir o seguinte componente filho ChildComponent:

import { Component } from "@angular/core";

@Component({
    selector: "child-comp",
    standalone: true,
    template: `<p>{{counter}}</p>`
})
export class ChildComponent {
    counter = 0;
    increment() { this.counter++; }
    decrement() { this.counter--; }
}

Este componente define uma variável counter que pode ser incrementada ou decrementada por meio dos métodos increment e decrement.

No código do componente principal, vamos incluir o componente filho:

import { Component } from "@angular/core";
import { ChildComponent } from "./child.component";

@Component({
    selector: "my-app",
    standalone: true,
    imports: [ChildComponent],
    template: `<child-comp #counter></child-comp>
                <button (click)="counter.increment()">+</button>
                <button (click)="counter.decrement()">-</button>`
})
export class AppComponent { }

Neste caso, a variável de template counter, definida dentro da tag <child-comp>, representará o componenteChildComponent. Assim, podemos referenciar o ChildComponent através dessa variável, vinculando os métodos increment e decrement aos eventos dos botões. Como resultado, ao clicar nos botões no componente principal, os métodos do componente filho serão chamados:

Variáveis Locais em Componentes de Angular

ViewChild

Entretanto, as variáveis de template têm suas limitações: elas não podem ser usadas fora do template, nem mesmo no código da classe do componente. Por exemplo, não podemos escrever o seguinte:

import { Component } from "@angular/core";
import { ChildComponent } from "./child.component";

@Component({
    selector: "my-app",
    standalone: true,
    imports: [ChildComponent],
    template: `<child-comp #counter></child-comp>
                <button (click)="increment()">+</button>
                <button (click)="decrement()">-</button>`
})
export class AppComponent { 

    increment() { this.counter++; }
    decrement() { this.counter--; }
}

Aqui, a propriedade this.counter não existe na classe AppComponent, ela existe apenas dentro do template.

Para permitir o acesso a métodos e outras funcionalidades do componente filho, podemos utilizar o decorador ViewChild. Esse decorador é aplicado a uma propriedade e recebe um seletor de elemento DOM que precisa ser monitorado. Se o elemento rastreado pelo seletor for alterado, ViewChild atualizará o estado da propriedade. Vamos modificar o componente principal da seguinte forma:

import { Component, ViewChild } from "@angular/core";
import { ChildComponent } from "./child.component";

@Component({
    selector: "my-app",
    standalone: true,
    imports: [ChildComponent],
    template: `<child-comp></child-comp>
                <button (click)="increment()">+</button>
                <button (click)="decrement()">-</button>`
})
export class AppComponent { 

    @ViewChild(ChildComponent, { static: false })
    private counterComponent: ChildComponent | undefined;
  
    increment() { this.counterComponent?.increment(); }
    decrement() { this.counterComponent?.decrement(); }
}

O primeiro parâmetro do decorador ViewChild indica o seletor do elemento que será monitorado. Esse seletor pode ser uma classe decorada com @Component, como a classe do componente ChildComponent. O segundo parâmetro, static, indica como será feito o rastreamento das alterações.

Vinculando ViewChild a Variáveis de Template

Embora no exemplo anterior não tenhamos utilizado variáveis, é possível vincular uma propriedade a uma variável de template usando o decorador ViewChild. Vamos modificar o código do componente principal:

import { Component, ViewChild, ElementRef } from "@angular/core";

@Component({
    selector: "my-app",
    standalone: true,
    imports: [],
    template: `<p #nameText>{{name}}</p>
                <p>{{nameText.textContent}}</p>
                <button (click)="change()">Change</button>`
})
export class AppComponent { 

    @ViewChild("nameText", { static: false })
    nameParagraph: ElementRef | undefined;
  
    name = "Tom";
  
    change() {
        if (this.nameParagraph !== undefined) {
            console.log(this.nameParagraph.nativeElement.textContent);
            this.nameParagraph.nativeElement.textContent = "hello";
        }
    }
}

Aqui, no template, definimos a variável nameText, que representa o parágrafo. No decorador ViewChild, passamos o nome dessa variável. Assim, a propriedade nameParagraph, à qual o decorador é aplicado, apontará para essa variável nameText. A propriedade nameParagraph é um objeto do tipo ElementRef | undefined, onde ElementRef é usado para referenciar elementos HTML.

Ao clicar no botão, o conteúdo textual dessa variável é exibido no console e alterado.

ContentChild

Além do ViewChild, podemos usar outro decorador chamado ContentChild para se conectar a variáveis de template, funcionando de maneira semelhante. Em que situação ele pode ser necessário? Suponha que no componente pai esteja definido o seguinte código:

import { Component } from "@angular/core";
import { ChildComponent } from "./child.component";

@Component({
    selector: "my-app",
    standalone: true,
    imports: [ChildComponent],
    template: `<child-comp>
                    <h3 #headerContent>Welcome {{name}}!</h3>
                </child-comp>`
})
export class AppComponent { 

    name = "Tom";
}

Aqui, definimos a variável #headerContent, que aponta para o elemento de título <h3>.

Como os dados do componente pai são passados diretamente para o componente filho, utilizaremos o elemento ng-content para receber esses dados no componente filho:

import { Component, ContentChild, ElementRef } from "@angular/core";

@Component({
    selector: "child-comp",
    standalone: true,
    template: `<ng-content></ng-content>
                <button (click)="change()">Change</button>`
})
export class ChildComponent { 

    @ContentChild("headerContent", { static: false })
    header: ElementRef | undefined;
  
    change() { 
        if (this.header !== undefined) {
            console.log(this.header);
            this.header.nativeElement.textContent = "Hello to the world!";
        }
    }
}

Para acessar as variáveis passadas pelo ng-content, o componente filho usa o decorador ContentChild. Nesse decorador, também passamos o nome da variável. A propriedade associada ao decorador será um objeto do tipo ElementRef | undefined, permitindo manipulações com esse objeto.

Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com