Minicurso Socket.IO - Parte 3 - Recebendo a notificação de Gol

Escrito por

Nas aulas anteriores do minicurso de Socket.IO, já preparamos o ambiente, conectamos o websocket do client para o servidor e agora vamos começar a emitir realmente as notificações.

A primeira coisa que vamos fazer é enviar o placar, vamos abrir o template match.ejs dentro de admin. A única coisa que temos de diferente é o time e os gols, nós vamos pegar esses dados e quando o usuário clicar em atualizar placar, iremos enviar isso ao servidor e ele vai disparar via socket.io para todos os clients.

Primeiramente lá no final, após incluir o footer, vamos adicionar um script:

1<script src="/js/admin.js"></script>

Esse script ainda não existe, vamos criar agora no diretório public/js, primeiro temos que descobrir qual o ID do botão do formulário, que é update-score e quando o usuário clicar nesse botão, eu quero dar um alert apenas para saber se está rodando:

1$(function)(){
2 $("#update-score").click(function(){
3 alert(1)
4 return false;
5 })
6});

Agora precisamos pegar os dois valores do jogo nos ID's score, e score-b, o notify-score e damos um console.log para saber se está tudo correto:

1$(function)(){
2 $("#update-score").click(function(){
3 const scoreA = $("#score-a").val();
4 const scoreB = $("#score-b").val();
5 const notify = $("#score-notify").val();
6 console.log(scoreA, scoreB, notofy)
7 return false;
8 })
9});

Perceba que o notify continuou com o value 1, isso acontece porque não está checando se esta checked ou não, então fazemos isso:

1const notify = $("#score-notify:checked").val()

Agora precisamos enviar isso para o express para ele distribuir via Socket.IO para todos os clients. Ao invés de mandar essa atualização via Socket.IO, eu posso mandar via API, salvar essa informação no banco e aí sim notificar (eu prefiro usar sempre essa forma para eu garantir  que eu só envie essa notificação para todo mundo).

1$(function)(){
2 $("#update-score").click(function(){
3 const scoreA = $("#score-a").val();
4 const scoreB = $("#score-b").val();
5 const notify = $("#score-notify").val();
6 $.post("/admin/match/0/score", post {
7 scoreA, scoreB, notify
8 }, function(data){
9 console.log(data)
10 })
11 return false;
12 })
13});

Ele não vai conseguir, pois não achou, mas se olharmos a conexão os dados já estão sendo enviados, então temos que receber esses dados lá. Vamos voltar em routes/admin.js e criar novo router:

1router.post("/match/:id/score", function(req, res) {
2 res.send(req.body)
3})

Fizemos isso para termos certeza que os dados estão chegando aqui, então vamos parar o servidor e a resposta do score vai ser exatamente o que eu enviei para ele, agora podemos processar esses dados. Vamos setar o valor no placar do banco de dados. Uma das formas que temos de fazer isso no low-db é pegando o índice do jogo e setar lá dentro falando qual o valor vou enviar para ele. Essa informação vai para todos os jogos, então eu devo emitir para todos que estão conectados no Socket.IO:

1router.post("/match/:id/score", function(req, res) {
2 db.set(
3 "matches[" + req.params.id + "].team-a.score",
4 parseInt(req.body.scoreA)
5 ).write()
6 db.set(
7 "matches[" + req.params.id + "].team-b.score",
8 parseInt(req.body.scoreB)
9 ).write()
10 io.emit("score", {
11 match: req.params.id,
12 scoreA: req.body.scoreA,
13 scoreB: req.body.scoreB,
14 notify: req.body.notify || 0,
15 })
16 res.send(req.body)
17})

Se o notify não existir, ele não vai ser enviado e eu mando zero para não notificar meus usuários. Agora está funcionando perfeitamente, se startarmos o servidor e dermos um f5, vai ser mostrado o valor enviado. Como eu tenho que dar f5 toda hora, tenho que receber no meu client a atualização que o jogo foi alterado, então vamos abrir na pasta js o arquivo match.js:

1$(function)(){
2 const socket = io();
3 socket.on('connect', function(){
4 console.log('conected');
5 })
6 socket.on('score', function(score){
7 console.log('score', score)
8 })
9})

Perceba que agora, ao atualizar o placar, o usuário recebe o objeto score, então precisamos checar se o jogo está na barra de cima e se é o jogo atual para atualizar na barra principal. Para isso vamos em match.ejs e na lista de jogo que fica na parte de cima, já temos um forEach que vai renderizar todos os jogos e temos para cada jogo um 'em' que tem o nome da class com uma referência para o jogo como um todo.

Vamos copiar esse trecho de código em negrito:

1<em class="match-<%- index %>-b">

Agora vamos voltar para nosso match do client em js/match.js e fazer o seguinte:

1$(function)(){
2 const socket = io();
3 socket.on('connect', function(){
4 console.log('conected');
5 })
6 socket.on('score', function(score){
7 console.log('score', score)
8 //na lista de jogos
9 $(". match-"+score.match+"-a").html(score.scoreA)
10 $(". match-"+score.match+"-b").html(score.scoreb)
11 })
12})

Perceba que em A nós escrevemos o valor de score.scoreA e o mesmo no B. Agora temos que atualizar a parte de baixo também, então nós temos o score-team-A e o valor do score por exemplo, porém como eu vou saber se esse jogo é o que eu estou atualmente? Em match.ejs, lá no final, antes do include do footer, vamos fazer um script que define uma constante:

1<script>
2const MATCH_INDEX = "<%- id %>";
3</script>

Quando faço isso, o match.index consegue acessar esse valor, então dentro do nosso match conseguimos checar se estamos em nosso jogo atual:

1socket.on('score', function(score){
2 console.log('score', score)
3 //na lista de jogos
4 $(". match-"+score.match+"-a").html(score.scoreA)
5 $(". match-"+score.match+"-b").html(score.scoreb)
6 //  atualizar o jogo
7 if(MATCH_INDEX == score.match){
8 $(".score-team-a").html(score.scoreA);
9 $(".score-team-b").html(score.scoreB);
10 if(score.notify=='1'){
11 console.log('notificar')
12 }
13 }
14})

Se o jogo é o que recebemos a notificação, nós notificamos esse gol. Em view/match, lá no final, temos uma div que é uma class goooolllll com um áudio, então se estivermos com o notificado ligado vamos dar um play nesse áudio, voltamos no código anterior e adicionamos o seguinte:

1if(score.notify=='1'){
2 console.log('notificar')
3 $('#audio-gol')[0].currentTime=0;
4 $('audio-gol')[0].play();
5}

Por que fizemos o notificar sim ou não? É possível notificar um gol e caso ele seja anulado, você tira o notificar e tira o placar sem alarmar todos. Podemos também fazer uma animação com aquele div que está ali

1if(score.notify=='1'){
2 console.log('notificar')
3 $('#audio-gol')[0].currentTime=0;
4 $('audio-gol')[0].play();
5 $('.goooolllll')addClass('goooolllll-anim')
6 $('.goooolllll-text')addClass('goooolllll-text-anim')
7 $('.goooolllll-text')on('transitionend webkitTransitionEnd oTransitionEnd', function(){
8 $('.goooolllll')removeClass('goooolllll-anim')
9 $('.goooolllll-text')removeClass('goooolllll-text-anim')
10 })
11}

Para testar temos que notificar em uma outra aba. Ao clicar, aparece duas classes com essa animação, quando a animação terminar nós removemos essa animação.

Na próxima aula vamos colocar a comunicação do lance a lance e dos vídeos, além de colocar o projeto em um servidor no digitalhost para conseguirmos acessar externamente.

Confira o passo a passo em vídeo:

Curta o DevPleno no Facebookinscreva-se no canal e não se esqueça de cadastrar seu e-mail para não perder as novidades. Abraço!

Evolua mais rápido

Junte-se a milhares de desenvolvedores no nosso time de alunos premium e alcance mais rápido o próximo nível da sua carreira.

Ver cursos Premium