Alura > Cursos de Front-end > Cursos de Angular > Conteúdos de Angular > Primeiras aulas do curso Angular: signals, services e router

Angular: signals, services e router

Entendendo hierarquia de componentes - Apresentação

Apresentando o instrutor e o curso

Olá! Bem-vindo a mais um curso da Formação Angular aqui na Alura. Meu nome é Rafael Paiva de Oliveira e serei o seu instrutor neste curso.

Audiodescrição: Rafael é uma pessoa de pele clara, usa óculos, tem cabelo muito curto e castanho, com entradas no cabelo e barba um pouco grisalha. Ele veste uma camiseta marrom clara e, ao fundo, há uma iluminação azul com alguns livros e enfeites na estante.

Explorando a comunicação entre componentes

Se no curso anterior demos os primeiros passos no framework, agora vamos nos aprofundar e falar mais sobre como escalar nossa aplicação, principalmente sobre a comunicação entre componentes pai e filho, usando @Input e @Output, que são a nova forma de comunicação utilizando o que há de mais moderno no framework hoje, que é o signal. É totalmente reativo, então vamos aprender a nova forma de comunicação dessa maneira.

Além disso, temos aquele problema clássico de como compartilhar nosso estado e informações entre telas, e para isso também aprenderemos a usar serviços e a injetá-los por meio de injeção de dependências. Também trabalharemos com rotas de forma profissional, atribuindo qual página vai em cada rota e permitindo que o Angular Router capture as propriedades e os parâmetros de rota. Com isso, conseguimos que a aplicação recarregue entre uma página e outra apenas os dados necessários, sem recarregar toda a página.

Implementando a Single Page Application

Com isso, temos a chamada Single Page Application (aplicação de página única), que é muito mais moderna e fluida para a pessoa usuária, pois não é necessário solicitar ao servidor a página a cada navegação. Assim, há também uma navegação inteligente.

Para colocar tudo isso em prática, vamos usar o UseDev, um projeto que estamos apresentando como uma solução completa. Teremos aqui um catálogo de produtos para escolher; por exemplo, ao clicar em um produto, veremos o detalhe do produto. Poderemos adicioná-lo ao carrinho e, ao clicar no ícone do carrinho, teremos a página do carrinho, podendo resumir as informações, verificar quais produtos foram adicionados, aumentar ou reduzir quantidades, calcular automaticamente os valores e eliminar produtos. Tudo isso será feito usando rotas e componentes.

Aplicando o conceito de Atomic Design

Aprenderemos a usar componentes mais focados na reutilização, mais genéricos e de apresentação, e como separar esses componentes em componentes inteligentes, aplicando o conceito de Atomic Design (design atômico). Para aproveitar bem este curso, é recomendado que tenhamos conhecimentos de HTML, CSS e JavaScript, além de saber o básico para criar uma aplicação Angular, conforme vimos no curso anterior.

Convidando para o início do curso

Estamos muito entusiasmados para aprender juntos e dar este passo adiante em nossos estudos de Angular. Vamos começar? Pegue seu café, abra o VSCode e vamos lá!

Entendendo hierarquia de componentes - Criando a primeira página

Iniciando o desenvolvimento da aplicação

Vamos começar a desenvolver nossa aplicação. Já visualizamos o projeto no Figma, agora vamos implementá-lo. Estamos com o VS Code aberto e na pasta do projeto UseDev. Se já passamos pela etapa de "Preparando o Ambiente" e clonamos o projeto, vamos explorar um pouco a estrutura de pastas.

O projeto é inicial e vem com um "Hello World". A única adição feita foi preparar o projeto para nós. Após clonar o projeto, devemos executar npm install para criar a pasta node_modules.

npm install

Existe uma ramificação chamada projeto-inicial, então vamos acessá-la com git checkout projeto-inicial.

git checkout projeto-inicial

Dentro dessa ramificação, já existem alguns arquivos iniciais para facilitar nosso desenvolvimento. Na pasta "public/images", há várias imagens que utilizaremos para desenvolver nossa interface, como o logo e a foto do produto. Também temos um arquivo com uma lista de produtos para trabalharmos e o style.css, que é o arquivo global. Ele já possui a fonte importada que usaremos e algumas classes prontas para agilizar o desenvolvimento do CSS.

Primeiro, vamos verificar a versão do Node que estamos usando com node -v. Estamos utilizando a versão 22.12, e o Angular que usaremos é a versão mais recente, a 21. Na documentação do Angular, há uma tabela de compatibilidade. Como desenvolveremos o projeto usando o Angular 21, se estivermos usando o Node 20, deve ser pelo menos a versão 20.19. Como estamos na versão 22, deve ser pelo menos a 22.12. Se tivermos uma versão superior, como a 22.18, não há problema. Vamos também verificar a versão do Angular instalada: estamos na versão 21.

Para instalar a ferramenta de linha de comando Angular CLI, usamos npm install -g @angular/cli.

npm install -g @angular/cli

Essa ferramenta é uma interface de linha de comando, então tudo que desenvolveremos — criar um novo projeto, criar um componente — será feito pelo terminal.

Executando o projeto e visualizando a tela inicial

Vamos colocar o projeto para rodar com npm start. No package.json, além das dependências, temos os scripts que executaremos, como npm start ou ng serve, que abrirá no porto 4200. Vamos executá-lo.

npm start

A tela inicial apresenta o "Hello World", como quando criamos um projeto novo.

Já visualizamos as telas que desenvolveremos. Neste vídeo, vamos desenvolver a primeira tela, que é a lista de produtos, a tela inicial do site. Alguns elementos se repetem, como o cabeçalho e o banner. Vamos usar o banner mais simples e não desenvolveremos a aplicação 100% agora, pois o foco é desenvolver a tela com os elementos que usaremos durante a aula. Se algum elemento não for desenvolvido agora e precisarmos dele mais tarde, podemos adicioná-lo depois.

No cabeçalho, faremos algo mais simples: apenas o logo e o carrinho de compras. Abaixo, desenvolveremos a lista de produtos, as "promoções especiais" e o rodapé em preto, com o logo verde, mas sem os demais itens que não são necessários. Tentaremos seguir o layout, mas simplificá-lo para se ajustar ao contexto que vamos desenvolver.

Estrutura do projeto

Vamos começar. No Angular, sempre temos o main, que inicializa a primeira aplicação. Todo projeto em Angular tem um primeiro componente, que é o app, carregado no index, e possui a parte de TypeScript, HTML e CSS. Vamos ao HTML, clicar ao lado e apagar o conteúdo. Salvamos com "Ctrl+S" e verificamos: o Angular já possui hot reload, então, cada vez que salvamos, a tela é atualizada. Agora está em branco.

Precisamos criar quatro partes: o cabeçalho, o banner, a lista de produtos (parte principal, corpo da página) e o rodapé. Vamos começar desenvolvendo o HTML. Colocaremos as etiquetas header, e dentro do header colocaremos o logo: image source.

<header>
    <img src="images/logo.svg" alt="Logo UseDev" />
</header>

Agora, vamos adicionar o carrinho. O carrinho tem um detalhe: colocaremos uma div ao redor do carrinho, chamaremos essa div de cart, pois não será apenas a imagem do carrinho.

<div class="cart">
    <img src="images/shopping_cart.svg" alt="ícone carrinho de compras"/>
    <span class="badge">0</span>
</div>

Deixaremos o main, que será a parte principal, e o footer, além da imagem do banner que está na pasta images/banner.png.

<main></main>
<footer></footer>
<img src="images/banner.png" class="banner" alt="Imagem banner" />

Ajustando o layout e aplicando estilos

Vamos revisar novamente. Agora já estamos posicionando os elementos. O reset.css que fiz, que é este inicial, vou comentar apenas para mostrar que todos os navegadores têm alguns valores CSS por padrão, e isso varia de navegador para navegador. Queremos que a pessoa que use nosso site tenha uma experiência consistente em qualquer navegador. Neste caso, ao inspecionar o elemento, percebemos que é o body que tem margem. O Chrome coloca uma margem no body que não queremos, aquela margem branca. Queremos que ocupe 100%, por isso usamos a estratégia de aplicar estilos a todos os elementos — por isso o asterisco — e gostamos de fazer esse reset.

No mais, não há muito mistério: no container usamos display:flex para alinhar verticalmente ao centro, e horizontalmente queremos colocar um em cada lado. Já deixamos algumas coisas adiantadas. Aqui, o banner; aquele span, aquele badge, é porque queremos que, à medida que desenvolvemos a aplicação, elementos sejam adicionados ao carrinho, mostrando esse número acima do carrinho. Assim, já deixamos pronto. Estamos fazendo toda a parte estática; apenas desenhando os elementos na tela, ainda não terá funcionalidade. Depois, começaremos a parte dinâmica para fazer com que as coisas funcionem.

O footer, o banner já temos, o logo também; acima temos o header, e agora falta o logo no footer, então vamos lá. Continuando, vamos colocar a imagem; é bastante parecida com a do footer, mas a diferença é que há um logo alternativo, que é verde, para dar melhor contraste com o preto, que é esta cor; logo verde. Colocamos o logo "os devs" em verde, e tem um pequeno texto que chamaremos de slogan; criamos uma classe chamada slogan, que é este texto.

<div class="container">
    <img src="images/logo-green.svg" alt="Logo UseDev Verde" />
    <div class="slogan">Hora de abraçar seu lado geek!</div>
</div>

Dessa forma, com o CSS que já preparamos para adiantar, também fica bastante responsivo para dispositivos móveis, o que nos ajudará a não precisar focar tanto em desenvolver a tela — o HTML e CSS — e sim focar na parte do curso, que é falar sobre componentização. Vamos criar este ambiente, depois trabalharemos sobre ele e o modificaremos. Só falta a parte principal, a do meio, então vamos lá. Esta parte tem um pequeno título, que acreditamos ser um H2, e depois uma lista onde usaremos um grid para posicionar, e então cada card terá a parte da imagem e a parte da informação com um resumo abaixo. Vamos lá.

Criando a lista de produtos

Dentro do main, vamos criar um H2; colocaremos "promos especiais", já está ficando com a fonte correta porque já fizemos o CSS.

<div class="container">
    <h2>Promos especiais</h2>
    <div class="product-list">
        <div class="product-card">
            <img class="product-image" src="images/product-capy.png" alt="Foto do produto Camiseta Capy"/>
            <div class="product-info">
                <div class="product-name">Camiseta Capy</div>
                <div class="product-price">R$ 28</div>
            </div>
        </div>
    </div>
</div>

Se quisermos testar como seria com outro card, se respeita o grid; então copiaremos 2, 3, 4, se copiarmos 4 vezes fica em 4 colunas; se colocarmos mais um, começará a descer para a próxima linha, igual no Figma; por quê? Aqui nos estilos temos nosso ProductList; está usando display:grid, então também tem isso; inclusive configuramos para telas pequenas, móveis, em telas pequenas está em 2 colunas; vejamos como fica em dispositivos móveis. Vamos inspecionar: abrir o F12, clicar com o botão direito, inspecionar, clicaremos na vista para ver como fica em celular; aqui deixamos apenas um, acreditamos que a visualização em móvel ficaria melhor, mas também fizemos certa responsividade, tudo isso já está pronto no CSS; se a tela for um pouco menor, um tablet, enfim, se ajustará ao conteúdo.

Então já temos uma base; como podemos ver todos os produtos? Lembram que comentamos que na pasta "src/app" há um arquivo chamado product.ts? Ele tem uma lista de produtos exportada com todos esses produtos para facilitar nossa vida. E também está o tipo; então criamos o tipo com name, description, price, como podemos fazer isso aqui?

export type Product = {
    id: number;
    name: string;
    description: string;
    price: number;
    imageUrl: string;
}

export const products: Product[] = [
    {
        id: 1,
        name: 'Camiseta Capy',
        description: 'Camiseta estampada com design exclusivo de capivara.',
        price: 25,
        imageUrl: 'images/product-capy.png',
    },
]

Implementando a lógica de produtos e carrinho

Vamos colocá-lo rapidamente em app.ts, que é o arquivo TypeScript, vamos criar um Product aqui, uma variável do tipo Signal, criaremos um Signal para controlar o estado; diremos que é do tipo Array de produtos, e o inicializaremos com o valor desse arquivo de produtos que criamos.

import { Product, products } from './product';

export class App {
  products = signal<Product[]>(products);
}

E aqui podemos fazer um for, por exemplo; em vez de ter vários cards, podemos deixar apenas um e colocar um for ao redor.

@for (product of products(); track product.id) {
    <div class="product-card">
        <img class="product-image" [src]="product.imageUrl" alt="Foto do produto Camiseta Capy"/>
        <div class="product-info">
            <div class="product-name">{{ product.name }}</div>
            <div class="product-price">R$ {{ product.price }}</div>
        </div>
    </div>
}

Agora temos oito produtos, e como faríamos para mudar a quantidade de artigos no carrinho? Se clicarmos para fazer um teste... vamos lá, vamos criar um método aqui, click: vamos ouvir o clique e criar um método chamado addToCart.

addToCart() {
    this.totalCartItems.update(value => value + 1);
}

Em nosso TS criaremos essa função addToCart, que quer adicionar algo ao carrinho, e o que faremos é criar outro signal para controlar o estado, chamaremos de totalCartItems; diremos que é um signal que começa em zero, e sempre que clicarmos nesse botão, sempre aumentaremos (update), então teremos um valor aqui e somaremos um, somaremos um; com isso podemos colocar essa variável no badge acima.

totalCartItems = signal(0);

E agora se clicarmos, está sendo adicionado ao carrinho; então, temos como criar a variável e controlá-la; podemos colocar até um if aqui também, e se não houver totalCartItems não queremos mostrar; só se existir, porque quando for zero não mostraremos nada.

@if (totalCartItems() > 0) {
    <span class="badge">{{ totalCartItems() }}</span>
}

Dessa forma, conseguimos criar a base da nossa aplicação e já temos a funcionalidade de adicionar produtos ao carrinho. No próximo vídeo, começaremos a dividir e criar os componentes, separá-los dentro da página. Nos vemos lá. Até mais!

Entendendo hierarquia de componentes - Separando por componentes

Continuando os estudos sobre componentes no Angular

Seguimos com nossos estudos. No último vídeo, criamos nosso header, a parte principal (main) e o footer, conforme o design da primeira página. Estamos desenvolvendo tudo de forma separada e organizada, utilizando as etiquetas semânticas do HTML. No entanto, estamos desenvolvendo tudo isso em um único componente.

No Angular, sempre há um componente que é criado primeiro, chamado app-root. Esse componente, na verdade, não existe como um elemento HTML; é um elemento criado pelo Angular. O Angular já cria esse componente para nós, e ele possui alguns valores. Basicamente, é uma classe em TypeScript com um decorator @Component que contém algumas metainformações.

O componente possui um selector, que é como o Angular entende que, ao ver a etiqueta app-root, sabe que esse elemento HTML não existe, mas buscará um elemento pelo prefixo. Sempre queremos que os elementos que criamos venham com esse prefixo app. Podemos alterar isso, mas esse é o padrão. Além disso, o componente pode importar outros componentes.

Por padrão, estamos usando HTML e CSS em arquivos separados. Tanto a parte do template quanto a parte do estilo são passadas para o componente, que então sabe onde está o template e pode se comunicar. Temos aqui os sinais de lista de produto e total de itens do carrinho, que estão fazendo o bind no HTML. Também criamos um evento apenas para teste. Quando esse evento ocorre no HTML, o eventBind chama o método test.

Embora esses arquivos estejam separados, eles formam um único componente. Na prática, dificilmente, a menos que estejamos desenvolvendo uma única página ou uma calculadora, trabalhamos com um único componente. Em uma aplicação real, que é bastante grande, começamos apenas com uma tela, que nem está funcionando 100%, e já temos uma quantidade significativa de linhas de código. Imagine criar todo o site em um único componente; seria difícil de manter no futuro. Não faz muito sentido.

Explorando a organização e criação de componentes no Angular

Facilita ter eventos e variáveis em um único lugar, mas isso impede que a aplicação cresça de forma adequada. Com 5 ou 6 telas, teremos elementos que queremos reutilizar. No caso, tivemos que fazer "Ctrl+C", "Ctrl+V" e acabamos usando o *ngFor. Na prática, precisamos usar o poder do Angular, que é o framework que possui o conceito de criar componentes. Não precisamos usar apenas o componente criado inicialmente; podemos criar nossos próprios componentes, o que proporciona uma certa organização, pois cada componente terá um foco.

Por exemplo, o cabeçalho será um componente, o banner será outro componente. Assim, ao clicar no index, sabemos que dentro do banner temos nosso app-root. Quando entramos no app.component, apenas olhando o HTML, já sabemos mais ou menos quais componentes o app.component precisa carregar, mesmo sem conhecer os detalhes. Se quisermos saber os detalhes de um componente específico, podemos entrar nele e fazer a manutenção.

Quando temos muitas coisas desordenadas, encontrar onde devemos dar manutenção se torna mais complicado. Da mesma forma, abordamos a parte de compatibilidade. Alguma dúvida? A documentação do Angular é muito rica e atualizada. Na documentação, encontramos o CLI, que é o Command Line Interface (Interface de Linha de Comando).

Ao trabalhar com Angular, instalamos com npm install -g @angular/cli. A partir daí, obtemos o comando ng. Para criar um novo projeto, utilizamos ng new, o que ajuda bastante. Quando vamos criar um novo componente, poderíamos simplesmente copiar e colar arquivos manualmente, mas isso consumiria muito tempo. Além do ng new para criar um novo projeto, temos o ng generate, que usaremos para criar componentes e serviços nos próximos vídeos.

Criando componentes e organizando a estrutura do projeto

Podemos usar ng generate ou sua abreviação ng g para criar várias coisas. Para criar componentes, usamos ng generate component ou ng g c. Vamos criar quatro componentes, representando cada parte da nossa aplicação. Primeiro, vamos parar a aplicação, limpar o terminal e executar ng generate component.

ng generate component

Se começarmos a criar componentes, eles ficarão soltos na pasta app. Queremos criar uma pasta de components para organizar melhor. Podemos criar diretamente components/header, por exemplo. Se passarmos a rota desejada com o nome, ele criará a pasta components, se não existir, e o header dentro dela.

ng generate component components/header

Se esquecermos de especificar component, podemos criar o footer para testar e usar a abreviação ng generate component para criar o footer.

ng g c footer

Vamos criar a parte principal da estrutura, chamada product-list. Se esquecermos de colocar dentro de components, podemos mover depois.

ng g c product-list

O padrão do Angular é criar a pasta e nomear os arquivos com hífen, enquanto a classe usa o padrão PascalCase, com a primeira letra maiúscula. Vamos criar o último componente, o banner, com ng generate component components/banner.

ng g c components/banner

Integrando componentes e ajustando estilos

Cada componente criado tem seu próprio seletor, como app-header. Para usá-lo, copiamos o seletor e o adicionamos no HTML do app component.

<app-header></app-header>

Angular recomenda usar o self-closing (auto-fechamento) para componentes.

<app-header />

Se der erro, é porque o Angular não reconhece o seletor como um elemento HTML normal. Precisamos importar o componente no app.ts, onde estão os imports.

import { Header } from './components/header/header';

Após importar, o Angular reconhecerá o componente.

Quando criamos um arquivo CSS, ele tem um escopo próprio. Podemos mover estilos específicos para dentro do componente correspondente, garantindo que não haja colisão de nomes. Isso encapsula o estilo dentro do componente, evitando conflitos.

Vamos remover o footer do app HTML e adicionar app-footer. Podemos importar diretamente o footer no arquivo. Agora, o footer está funcionando. Precisamos colocar o código HTML dentro do footer e mover seu estilo correspondente.

<app-footer />

Estamos organizando a aplicação desde o início, observando padrões de layout que fazem sentido dividir em componentes. Isso facilita a reutilização e manutenção. Quando criamos um componente, ele pode importar outros componentes, como um lego.

Vamos mover o estilo do banner para seu arquivo CSS correspondente. O mesmo faremos com o product-list, movendo o CSS e a lista de produtos para o componente responsável. O app não precisa saber o que há dentro do product-list, apenas importa os componentes necessários.

No index.html, o app-root inicia a aplicação, importando componentes como header, banner, product-list e footer.

<app-header />
<app-banner />
<app-product-list />
<app-footer />

Essa organização faz sentido e facilita a manutenção.

Na próxima aula, trabalharemos mais sobre como um componente pode ter outro componente, criando um product-card mais reutilizável. Vamos praticar juntos como criar melhores componentes e organizar melhor nossa aplicação. Nos vemos na próxima aula!

Sobre o curso Angular: signals, services e router

O curso Angular: signals, services e router possui 299 minutos de vídeos, em um total de 45 atividades. Gostou? Conheça nossos outros cursos de Angular em Front-end, ou leia nossos artigos de Front-end.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Angular acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas