Boas-vindas a mais este curso de JavaScript! Me chamo Nayanne Batista e serei a sua instrutora.
Audiodescrição: Nayanne se declara como uma mulher de pele morena, com olhos e cabelos castanhos escuros, e está vestindo uma camisa laranja. Ao fundo, há uma estante com livros e decorações, além de uma janela à esquerda com iluminação verde.
Evoluiremos o projeto Memoteca, um mural de pensamentos que conta com um formulário intitulado "Adicione um pensamento novo" para adicionar conteúdo, autoria e data, além de um mural com os pensamentos preferidos cadastrados na parte inferior, denominado "Meu Mural".
Nesta aplicação, implementaremos o campo de data no formulário, permitindo que você aprenda a manipular datas em JavaScript e a personalizá-las para apresentá-las de forma agradável à pessoa usuária. Além disso, integraremos uma busca typeahead ("digitação antecipada"), que sugere resultados dinamicamente conforme o texto é digitado.
Implementaremos também a funcionalidade de favoritar pensamentos clicando no ícone de coração na parte inferior direita de um dos pensamentos do "Meu Mural", além de aplicar validações no formulário com o uso de regex para evitar a adição de pensamentos duplicados.
Utilizaremos diversos métodos do ES6+ (ECMAScript 6 e versões posteriores), como o replaceAll
, o spreadOperator
e a desestruturação, além de outros métodos e recursos do JavaScript.
Os pré-requisitos para este curso incluem conhecimentos em HTML, CSS e JavaScript, especialmente sobre funções e requisições HTTP. É recomendável também que você tenha concluído os cursos anteriores da formação.
Estou muito animada para começar, e espero que você também esteja empolgado. Vamos lá!
Chegou o momento de aprimorar a aplicação Memoteca. Neste curso, adicionaremos diversas funcionalidades para tornar nosso projeto mais completo e robusto, além de melhorar a experiência da pessoa usuária.
O projeto é o "Mural de Pensamentos". Com o crescimento da aplicação e o cadastro de novos pensamentos, torna-se mais difícil encontrar um pensamento específico.
Imagine um e-commerce com milhares de produtos. Mesmo utilizando filtros por categoria, pode ser difícil localizar um produto específico entre tantos outros.
Para resolver esse problema, seria ideal implementar uma funcionalidade que facilite a busca e a localização desses produtos.
Vamos ao Figma!
Abaixo do título "Meu Mural", há um campo de busca. A ideia é permitir que a pessoa digite uma palavra-chave ou termo e encontre o que procura. Neste vídeo, vamos começar a implementar essa funcionalidade, dividindo o processo em várias etapas.
Etapas que seguiremos:
A primeira etapa é a parte da interface. Começamos adicionando o campo de busca no mural. Em seguida, avançamos para o envio das palavras-chave para a API e o retorno dos pensamentos necessários.
Acessamos a aplicação e abrimos o VSCode. Com o comando "Ctrl + J" para abrir o terminal, verificamos que o back-end já está em execução, pois digitamos npm start
.
npm start
Terminal da instrutora:
Endpoints:
No arquivo index.html
, adicionamos um novo bloco para representar o campo de busca. Observamos que já temos uma section
na linha 30, que representa o container do formulário (<section id="form-container">
), e outra section
na linha 56, que representa o container da lista de pensamentos (<section id="lista-pensamentos-container">
).
Adicionaremos uma nova section
para representar o container do campo de busca.
É sempre importante utilizar HTML o mais semântico possível. Em vez de adicionar várias divs
, optamos por usar tags que representem melhor o que estamos fazendo no código. Abaixo do h3
, na linha 58, criamos uma nova section
. Para identificar claramente essa seção, adicionamos um id
com o valor busca-container
.
index.html
<!-- código omitido -->
<section id="busca-container">
</section>
<!-- código omitido -->
Dentro da nova section
, incluímos um input
para permitir que a pessoa digite. Utilizamos o <input type="text">
, quebramos para facilitar a visualização e definimos o id
como campo-busca
, que poderá ser usado posteriormente para estilizar. Adicionamos também um placeholder
com a mensagem "O que você procura?"
.
<!-- código omitido -->
<section id="busca-container">
<input
type="text"
id="campo-busca"
placeholder="O que você procura?" />
</section>
<!-- código omitido -->
Além do input
, adicionamos também uma imagem da lupa. Usamos então
img
e um src
(source). O caminho da imagem é assets/imagens/lupa.png
. Como essa imagem é apenas decorativa, não adicionamos a propriedade alt, pois, nesses casos, não é obrigatório incluir essa descrição.
<!-- código omitido -->
<section id="busca-container">
<input
type="text"
id="campo-busca"
placeholder="O que você procura?" />
<img src="assets/imagens/lupa.png" alt="">
</section>
<!-- código omitido -->
Agora, voltamos à aplicação. Observamos que o layout está um pouco desalinhado, com a lupa à direita fora do campo de busca. Para corrigir isso, adicionamos uma classe à imagem da lupa. Definimos a classe como lupa
.
<!-- código omitido -->
<section id="busca-container">
<input
type="text"
id="campo-busca"
placeholder="O que você procura?" />
<img class="lupa" src="assets/imagens/lupa.png" alt="">
</section>
<!-- código omitido -->
Essas classes e IDs já estão sendo referenciados no nosso CSS, em styles.css
.
styles.css
# código omitido
#busca-container {
display: flex;
align-items: center;
margin-top: 56px;
width: 100%;
max-width: 600px;
margin: 56px auto;
padding: 0 16px;
}
#campo-busca {
flex: 1;
width: 572px;
height: 48px;
padding: 8px 16px;
border-radius: 32px;
border: 1px solid #144480;
font-family: "Poppins", sans-serif;
font-size: 16px;
font-weight: 400;
outline: none;
}
.lupa {
margin-left: -40px;
width: 24px;
height: 24px;
}
# código omitido
Estamos estilizando tanto o container
quanto o input
e a imagem. Assim, ao voltar para a aplicação, observamos o campo de busca com a lupa corretamente posicionada dentro dele.
Completamos o primeiro passo: modificamos a interface para incluir um campo de busca, permitindo que a pessoa digite um termo para realizar a busca. Observamos que não há um botão para buscar, mas isso será abordado em vídeos futuros, onde explicaremos por que apenas o campo de busca é suficiente por enquanto.
No próximo passo, iremos ao arquivo da API, onde já temos algumas requisições configuradas para enviar o termo de busca. A implementação detalhada será discutida no próximo vídeo!
No vídeo anterior, adicionamos o campo de busca na aplicação. No entanto, ele ainda não está funcionando porque precisamos integrar essa funcionalidade no arquivo api.js
, que é responsável por enviar as requisições para a API.
Acessamos o arquivo api.js
no VSCode. O que precisamos fazer é adicionar uma nova busca. Já temos algumas buscas implementadas na aplicação, como a função buscarPensamentos()
, que retorna todos os pensamentos, e a função buscarPensamentoPorId(id)
, que retorna um pensamento específico com base no ID.
buscarPensamentosPorTermo()
Desta vez, desejamos buscar um conjunto de pensamentos que contenham uma palavra-chave, que a pessoa vai digitar, seja no conteúdo ou na autoria. Para isso, criamos uma nova função. Na linha 58, digitaremos async
e chamaremos essa função de buscarPensamentosPorTermo()
. Precisamos passar como parâmetro o termo
que a pessoa vai digitar.
api.js
// código omitido
async buscarPensamentosPorTermo(termo) {
}
// código omitido
Dentro dessa função, precisamos primeiro obter todos os pensamentos. Após isso, podemos filtrá-los para identificar quais contêm o termo pesquisado. Para obter todos os pensamentos, utilizaremos a função buscarPensamentos()
, pois já temos essa funcionalidade implementada e não precisamos fazer uma nova requisição.
Criamos uma constante chamada pensamentos
e atribuímos a ela o valor retornado pela função this.buscarPensamentos()
, usando await
.
// código omitido
async buscarPensamentosPorTermo(termo) {
const pensamentos = await this.buscarPensamentos()
}
// código omitido
Assim, pensamentos
conterá todos os pensamentos, pois a função buscarPensamentos()
retorna todos os dados dos pensamentos, conforme definido na linha 4 da função.
Com isso, temos todos os pensamentos armazenados na constante pensamentos
.
pensamentosFiltrados
Criaremos uma constante chamada pensamentosFiltrados
. Para obter esses pensamentos filtrados, faremos um filtro no array pensamentos. No JavaScript, utilizamos o método filter
para essa tarefa, e o nome do método é bem sugestivo para sua função.
Passaremos pensamentos.filter
, onde fornecemos um callback que recebe cada pensamento e uma condição. Se o pensamento atender a essa condição, ele será incluído no array pensamentosFiltrados
; caso contrário, não será incluído. Inserimos uma arrow function dentro dos parênteses do pensamentos.filter()
.
// código omitido
async buscarPensamentosPorTermo(termo) {
const pensamentos = await this.buscarPensamentos()
const pensamentosFiltrados = pensamentos.filter(pensamento => {
})
}
// código omitido
Desejamos que o método filter
retorne todos os pensamentos que atendem à condição. Para isso, usaremos return
para incluir o pensamento.conteudo
. Também aplicaremos o método toLowerCase()
a esse conteúdo.
// código omitido
async buscarPensamentosPorTermo(termo) {
const pensamentos = await this.buscarPensamentos()
const pensamentosFiltrados = pensamentos.filter(pensamento => {
return pensamento.conteudo.toLowerCase()
})
}
// código omitido
Esse método converte o texto para letras minúsculas para garantir que a busca não seja case-sensitive (sensível a maiúsculas e minúsculas). Assim, asseguramos que o termo de busca seja encontrado independentemente de como o texto está formatado.
Desejamos que, se a pessoa digitar "chaves" em minúsculas, maiúsculas ou caixa alta, isso não influencie na busca. Para garantir isso, converteremos o conteúdo digitado e o conteúdo dos pensamentos para letras minúsculas. Assim, a busca será realizada de forma uniforme, independentemente do formato das letras.
Para converter o termo digitado para letras minúsculas, criaremos uma constante chamada termoEmMinusculas
após pensamentos
, que receberá o valor de termo.toLowerCase()
.
// código omitido
async buscarPensamentosPorTermo(termo) {
const pensamentos = await this.buscarPensamentos()
const termoEmMinusculas = termo.toLowerCase()
const pensamentosFiltrados = pensamentos.filter(pensamento => {
return pensamento.conteudo.toLowerCase()
})
}
// código omitido
Assim, independentemente de como a pessoa digitar o termo, ele será convertido para minúsculas. Compararemos esse termo convertido com o conteúdo do pensamento
, que também será convertido para minúsculas, garantindo uma busca consistente.
Após a comparação, desejamos verificar se o conteúdo do pensamento inclui o termo pesquisado. Para isso, usaremos o método includes()
do JavaScript após o toLowerCase()
. Esse método verifica se o termo está presente no conteúdo, retornando true
se estiver e false
se não estiver. Passaremos o termoEmMinusculas
para essa verificação.
// código omitido
async buscarPensamentosPorTermo(termo) {
const pensamentos = await this.buscarPensamentos()
const termoEmMinusculas = termo.toLowerCase()
const pensamentosFiltrados = pensamentos.filter(pensamento => {
return pensamento.conteudo.toLowerCase().includes(termoEmMinusculas)
})
}
// código omitido
Vamos criar um filtro que permita pesquisar tanto pelo conteúdo quanto pela autoria. Digitamos duas barras verticais (||
), que representam o operador "ou". Abaixo, inserimos o código: pensamento.autoria.toLowerCase().includes(termoEmMinusculas)
.
Desejamos que sejam retornados os pensamentosFiltrados
.
// código omitido
async buscarPensamentosPorTermo(termo) {
const pensamentos = await this.buscarPensamentos()
const termoEmMinusculas = termo.toLowerCase()
const pensamentosFiltrados = pensamentos.filter(pensamento => {
return pensamento.conteudo.toLowerCase().includes(termoEmMinusculas) || pensamento.autoria.toLowerCase().includes(termoEmMinusculas)
})
return pensamentosFiltrados
}
// código omitido
Após obter esses resultados, adicionaremos o tratamento de erros.
Para manter o padrão utilizado em outras requisições, usaremos o bloco try-catch
. Na linha 59, digitamos try
e abrimos os colchetes. Movemos o conteúdo da linha 62 até a linha 69 para dentro do bloco try
(todo o código que montamos).
Na linha 68, após o primeiro fechamento de chaves depois do return
, adicionamos um catch(error)
. Se ocorrer um erro, usamos alert()
para informar a pessoa usuária com a mensagem "Erro ao filtrar pensamentos"
. Em seguida, lançamos o erro com throw error
.
// código omitido
async buscarPensamentosPorTermo(termo) {
try {
const pensamentos = await this.buscarPensamentos()
const termoEmMinusculas = termo.toLowerCase()
const pensamentosFiltrados = pensamentos.filter(pensamento => {
return pensamento.conteudo.toLowerCase().includes(termoEmMinusculas) ||
pensamento.autoria.toLowerCase().includes(termoEmMinusculas)
})
return pensamentosFiltrados
} catch (error) {
alert("Erro ao filtrar pensamentos")
throw error
}
}
// código omitido
Com isso, temos uma nova requisição na API responsável pela lógica de filtragem e pela verificação de se os pensamentos contêm o termo digitado pela pessoa.
No entanto, ao voltar à aplicação e digitar qualquer coisa, não veremos a atualização da lista ainda, pois precisamos fazer algumas modificações na interface. Abordaremos essas alterações nos próximos vídeos!
O curso JavaScript: evoluindo a sua aplicação com ES6+ possui 133 minutos de vídeos, em um total de 61 atividades. Gostou? Conheça nossos outros cursos de JavaScript 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:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.