Desenvolva um aplicativo de pesquisas em tempo real com Node.js, Express, AngularJS e MongoDB

05/Dez/2014
PDF (317 KB)
 

Desenvolva um aplicativo de pesquisas em tempo real com Node.js, AngularJS e MongoDB

04:53  |  Transcricao
Author photo - Joe Lennon

Joe Lennon

CTO at ePubDirect

@joelennon

Inscreva-se no IBM Bluemix
Esta plataforma em nuvem fornece muitos serviços grátis, tempos de execução e infraestrutura para ajudar a desenvolver e implementar rapidamente o seu próximo aplicativo móvel ou da web.

Recentemente, enquanto ensinava HTML5 a um grupo grande de estudantes, eu queria fazer uma pesquisa com eles e exibir os resultados atualizados em tempo real. Decidi desenvolver rapidamente um aplicativo de pesquisa para fazer isso. Queria uma arquitetura simples e não muitas linguagens e estruturas diferentes. Por isso, decidi usar JavaScript para tudo — Node.js e Express para o lado do servidor, MongoDB para o banco de dados e AngularJS para a interface com o usuário do front-end.

Essa pilha MEAN (Mongo, Express, Angular, Node) pode um dia ultrapassar a simplicidade da pilha LAMP (Linux, Apache, MySQL, PHP) para desenvolvimento e implementação de aplicativos da web.

Escolhi usar DevOps Services (antigo JazzHub) para gerenciar o código fonte do meu projeto. Além de disponibilizar um sistema completo de controle de versão para meu código, ele também possui um IDE online para editar o código na nuvem, além de ter abundantes recursos agile para gerenciamento de projeto. O DevOps Services também pode ser integrado facilmente com o Eclipse, que possui plug-ins para permitir implementação com um clique em plataformas como Bluemix ou Cloud Foundry.

O que será necessário para desenvolver o aplicativo

 

Leia:Node.js— além do básico

Etapa 1. Desenvolver um backend Express básico

 

No Eclipse, passe para a perspectiva Node e crie um projeto Node Express. Se você criar um projeto do DevOps Services como eu fiz, dê ao projeto Node o mesmo nome. Deixe Jade selecionado como mecanismo de modelo. O Eclipse fará automaticamente o download dos módulos npm necessários para criar um aplicativo Express simples.

Execute o aplicativo Express

 

No Project Explorer, localize app.js na raiz do projeto, clique com o botão direito e escolha Run As > Node Application. Isso iniciará um servidor da web e implementará o aplicativo nele. Em seguida, abra um navegador e acesse http://localhost:3000.

Figura 1. Aplicativo Starter Express
Starter Express app

Configure o frontend básico

 

O aplicativo de pesquisas usa a estrutura Bootstrap para a interface de usuário e layout gerais. Vamos fazer algumas alterações ao aplicativo Express agora para refletir isso. Primeiro, abra routes/index.js e altere a propriedade de título para Polls:

Lista 1. routes/index.js
        exports.index = function(req, res){
             res.render('index', { title: 'Polls' });
         };

Em seguida, altere o modelo views/index.jade para incluir o Bootstrap. Jade é uma linguagem de modelo abreviada que é compilada em HTML. Ela usa indentação para não precisar fechar tags, o que reduz significativamente o tamanho dos modelos. Você usará Jade apenas para o layout da página principal. Você usará modelos parciais Angular para adicionar funcionalidade a essa página na próxima etapa.

Lista 2. views/index.jade
        doctype 5
        html(lang='en')
          head
            meta(charset='utf-8')
            meta(name='viewport', content='width=device-width,
	initial-scale=1, user-scalable=no')
            title= title
            link(rel='stylesheet', href='//netdna.bootstrapcdn.com/bootstrap/3.0.1/
	css/bootstrap.min.css')
            link(rel='stylesheet', href='/stylesheets/style.css')
          body
            nav.navbar.navbar-inverse.navbar-fixed-top(role='navigation')
              div.navbar-header
                a.navbar-brand(href='#/polls')= title
            div.container
              div

Para ver as alterações no aplicativo, elimine o processo do servidor da web no Eclipse e execute o arquivo app.js novamente:

Figura 2. Padrão do aplicativo de pesquisas

Observação: ao usar modelos Jade, tenha cuidado para indentar o código apropriadamente, ou haverá problemas. Evite também misturar estilos de indentação, pois ocorrerão erros no Jade caso isso seja feito.

Etapa 2.Criar a experiência do usuário de frontend com o AngularJS

 

Para começar a usar o Angular, é preciso primeiro incluí-lo e adicionar algumas diretivas na página HTML. No modelo views/index.jade, altere o elemento html para o seguinte:
html(lang='en', ng-app='polls').

No bloco de cabeçalho desse arquivo, adicione os seguintes elementos de script:

Lista 3. Elementos de script para carregar o Angular e o módulo Angular Resource
        script(src='//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js')
        script(src='//ajax.googleapis.com/ajax/libs/angularjs/1.0.8
/angular-resource.min.js')

Em seguida, altere o elemento body no modelo, adicionando um atributo ng-controller (para posteriormente conectar a interface com o usuário ao código de lógica do controlador):
body(ng-controller='PollListCtrl').

Por fim, altere o último elemento div no modelo para incluir um atributo ng-view : div(ng-view).

Desenvolva o módulo Angular

 


Um recurso impressionante no Angular é a ligação de dados, que atualiza automaticamente as visualizações quando os modelos de backend mudam. Isso reduz a quantidade de JavaScript que precisa ser escrita, pois abstrai a tarefa complicada de manipular o DOM.

Por padrão, o Express publica recursos estáticos como arquivos de origem JavaScript, folhas de estilo CSS e imagens do diretório público no projeto. No diretório público, crie um novo subdiretório chamado javascripts. Nesse subdiretório, crie um arquivo chamado app.js. Esse arquivo irá conter o módulo Angular do aplicativo, definindo as rotas e os modelos a serem usados para a interface com o usuário:

Lista 4. public/javascripts/app.js
        angular.module('polls', [])
          .config(['$routeProvider', function($routeProvider) {
            $routeProvider.
                            when('/polls', { templateUrl: 'partials/list.html', controller: 
PollListCtrl }).
              when('/poll/:pollId', { templateUrl: 'partials/item.html', controller: 
PollItemCtrl }).
              when('/new', { templateUrl: 'partials/new.html', controller: 
PollNewCtrl }).
              otherwise({ redirectTo: '/polls' });
          }]);

Os controladores Angular definem o escopo do aplicativo, fornecendo dados e métodos para a ligação das visualizações.

Lista 5. public/javascript/controllers.js
        // Managing the poll list
        function PollListCtrl($scope) {
          $scope.polls = [];
        }
        // Voting / viewing poll results
        function PollItemCtrl($scope, $routeParams) {
          $scope.poll = {};
          $scope.vote = function() {};
        }
        // Creating a new poll
        function PollNewCtrl($scope) {
          $scope.poll = {
            question: '',
            choices: [{ text: '' }, { text: '' }, { text: '' }]
          };
          $scope.addChoice = function() {
            $scope.poll.choices.push({ text: '' });
          };
          $scope.createPoll = function() {};
        }

Crie os modelos HTML parciais

 

Para renderizar os dados dos controladores, o Angular usa modelos HTML parciais para permitir o uso de valores temporários e expressões para incluir dados e realizar operações como condicionais e iteradores. No diretório público, crie um subdiretório chamado partials. Criaremos três parciais para o aplicativo. A primeira parcial exibe a lista de pesquisas disponíveis, e usaremos o Angular para filtrar facilmente essa lista por um campo de pesquisa.

Lista 6. public/partials/list.html
        <div class="page-header">
          <h1>Poll List</h1>
        </div>
        <div class="row">
          <div class="col-xs-5">
            <a href="#/new" class="btn btn-default"><span class="glyphicon 
glyphicon-plus"></span> New Poll</a>
          </div>
          <div class="col-xs-7">
            <input type="text" class="form-control" ng-model="query" 
placeholder="Search for a poll">
          </div>
        </div>
        <div class="row"><div class="col-xs-12">
<hr></div></div>
        <div class="row" ng-switch on="polls.length">
          <ul ng-switch-when="0">
            <li><em>No polls in database. Would you like to
 <a href="#/new">create one</a>?</li>
          </ul>
          <ul ng-switch-default>
            <li ng-repeat="poll in polls | filter:query">
              <a href="#/poll/{{poll._id}}">{{poll.question}}</a>
            </li>
          </ul>
        </div>
        <p>&nbsp;</p>

A segunda parcial permite que o usuário visualize a pesquisa. Ela usa a diretiva de alternância para determinar se o usuário votou. Com base nessa determinação, será exibido um formulário para votar na pesquisa ou um gráfico com os resultados.

Lista 7. public/partials/item.html
        <div class="page-header">
          <h1>View Poll</h1>
        </div>
        <div class="well well-lg">
          <strong>Question</strong><br>{{poll.question}}
        </div>
        <div ng-hide="poll.userVoted">
          <p class="lead">Please select one of the following options.</p>
          <form role="form" ng-submit="vote()">
            <div ng-repeat="choice in poll.choices" class="radio">
              <label>
                <input type="radio" name="choice" ng-model="poll.userVote" 
	value="{{choice._id}}">
                {{choice.text}}
              </label>
            </div>
            <p><hr></p>
            <div class="row">
              <div class="col-xs-6">
                <a href="#/polls" class="btn btn-default" role="button"><span
class="glyphicon glyphicon-arrow-left"></span> Back to Poll
              </div>
              <div class="col-xs-6">
                <button class="btn btn-primary pull-right" type="submit">
	Vote &raquo;</button>
              </div>
            </div>
          </form>
        </div>
        <div ng-show="poll.userVoted">
          <table class="result-table">
            <tbody>
              <tr ng-repeat="choice in poll.choices">
                <td>{{choice.text}}</td>
                <td>
                  <table style="width: {{choice.votes.length
	/poll.totalVotes*100}}%;">
                    <tr><td>{{choice.votes.length}}</td></tr>
                  </table>
                </td>
              </tr>
            </tbody>
          </table>  
          <p><em>{{poll.totalVotes}} votes counted so far. <span 
ng-show="poll.userChoice">You voted for <strong>{{poll.userChoice.text}}
</strong>.</span></em></p>
          <p><hr></p>
          <p><a href="#/polls" class="btn btn-default" role="button">
<span class="glyphicon glyphicon-arrow-left"></span> Back to 
Poll List</a></p>
        </div>
        <p>&nbsp;</p>

A terceira e última parcial define o formulário que permite ao usuário criar pesquisas. Ela solicita que usuário insira uma pergunta e três escolhas. Há um botão para adicionar mais escolhas. Posteriormente iremos verificar se o usuário inseriu ao menos duas escolhas — pois não seria uma pesquisa adequada sem algumas escolhas.

Lista 8. public/partials/new.html
        <div class="page-header">
          <h1>Create New Poll</h1>
        </div>
        <form role="form" ng-submit="createPoll()">
          <div class="form-group">
            <label for="pollQuestion">Question</label>
            <input type="text" ng-model="poll.question" class="form-control" 
id="pollQuestion" placeholder="Enter poll question">
          </div>
          <div class="form-group">
            <label>Choices</label>
            <div ng-repeat="choice in poll.choices">
              <input type="text" ng-model="choice.text" class="form-control" 
placeholder="Enter choice {{$index+1}} text"><br>
            </div>
          </div>    
          <div class="row">
            <div class="col-xs-12">
              <button type="button" class="btn btn-default" ng-click=
"addChoice()"><span class="glyphicon glyphicon-plus">
</span> Add another</button>
            </div>
          </div>
          <p><hr></p>
          <div class="row">
            <div class="col-xs-6">
              <a href="#/polls" class="btn btn-default" role="button">
<span class="glyphicon glyphicon-arrow-left"></span> 
Back to Poll List</a>
            </div>
            <div class="col-xs-6">
              <button class="btn btn-primary pull-right" type="submit">
	Create Poll &raquo;</button>
            </div>
          </div>
          <p>&nbsp;</p>
        </form>

Por fim, para exibir os resultados, precisamos adicionar algumas declarações de CSS ao arquivo style.css. Substitua o conteúdo do arquivo por isto:

Lista 9. public/stylesheets/style.css
        body { padding-top: 50px; }
        .result-table {
          margin: 20px 0;
          width: 100%;
          border-collapse: collapse;
        }
        .result-table td { padding: 8px; }
        .result-table > tbody > tr > td:first-child {
          width: 25%;
          max-width: 300px;
          text-align: right;
        }
        .result-table td table {
          background-color: lightblue;
          text-align: right;
        }

Nesse momento, se você executar o aplicativo verá uma lista de pesquisas vazia. Se você tentar criar uma pesquisa, verá o formulário e poderá adicionar alternativas, mas não poderá salvar a pesquisa. Iremos juntar tudo isso na próxima etapa.

Etapa 3.Armazenar dados no MongoDB usando Mongoose

 

Assista:Uma introdução ao MongoDB

Para armazenar dados, o aplicativo usa o driver MongoDB e módulos npm Mongoose. Eles permitem que o aplicativo se comunique com o banco de dados MongoDB. Para obter esses módulos, abra o arquivo package.json no diretório-raiz do aplicativo e, na seção de dependências, inclua estas linhas:.

Lista 10. Incluir linhas na seção de dependências
        "mongodb": ">= 1.3.19",
        "mongoose": ">= 3.8.0",

Salve o arquivo, clique com o botão direito nele no Project Explorer e escolha Run As > npm install. Isso instalará os módulos npm e dependências adicionais que existam.

Crie um modelo Mongoose

 

Crie um subdiretório na raiz do aplicativo chamado models e, nesse subdiretório, crie um arquivo chamado Poll.js. É aí que definiremos o modelo Mongoose, que será usado para consultar e salvar dados no MongoDB de uma maneira estruturada.

Lista 11. models/Poll.js
        var mongoose = require('mongoose');
        var voteSchema = new mongoose.Schema({ ip: 'String' });
        var choiceSchema = new mongoose.Schema({
          text: String,
          votes: [voteSchema]
        });
        exports.PollSchema = new mongoose.Schema({
          question: { type: String, required: true },
          choices: [choiceSchema]
        });

Defina rotas de API para armazenamento de dados

 

Em seguida, defina algumas rotas no arquivo app.js na raiz do aplicativo para criar terminais JSON que podem ser usados para consultar e atualizar o MongoDB a partir do código Angular do lado do cliente. Localize a linha app.get('/', routes.index) e inclua o código a seguir após a linha :

Lista 12. Crie terminais JSON
        app.get('/polls/polls', routes.list);
        app.get('/polls/:id', routes.poll);
        app.post('/polls', routes.create);

Agora é necessário implementar estas funções. Substitua o conteúdo do arquivo routes/index.js por este código::

Lista 13. routes/index.js
        var mongoose = require('mongoose');
        var db = mongoose.createConnection('localhost', 'pollsapp');
        var PollSchema = require('../models/Poll.js').PollSchema;
        var Poll = db.model('polls', PollSchema);
        exports.index = function(req, res) {
          res.render('index', {title: 'Polls'});
        };
        // JSON API for list of polls
        exports.list = function(req, res) {
          Poll.find({}, 'question', function(error, polls) {
            res.json(polls);
          });
        };
        // JSON API for getting a single poll
        exports.poll = function(req, res) {
          var pollId = req.params.id;
          Poll.findById(pollId, '', { lean: true }, function(err, poll) {
            if(poll) {
              var userVoted = false,
                  userChoice,
                  totalVotes = 0;
              for(c in poll.choices) {
                var choice = poll.choices[c];
                for(v in choice.votes) {
                  var vote = choice.votes[v];
                  totalVotes++;
                  if(vote.ip === (req.header('x-forwarded-for') || req.ip)) {
                    userVoted = true;
                    userChoice = { _id: choice._id, text: choice.text };
                  }
                }
              }
              poll.userVoted = userVoted;
              poll.userChoice = userChoice;
              poll.totalVotes = totalVotes;
              res.json(poll);
            } else {
              res.json({error:true});
            }
          });
        };
        // JSON API for creating a new poll
        exports.create = function(req, res) {
          var reqBody = req.body,
              choices = reqBody.choices.filter(function(v) { return v.text != ''; }),
              pollObj = {question: reqBody.question, choices: choices};
          var poll = new Poll(pollObj);
          poll.save(function(err, doc) {
            if(err || !doc) {
              throw 'Error';
            } else {
              res.json(doc);
            }
          });
        };

Vincule os dados ao frontend com serviços Angular

 

Neste momento, o backend está configurado para permitir consultar e salvar pesquisas no banco de dados, mas é preciso fazer algumas alterações no Angular para que se comunique com ele. Isso é fácil com serviços Angular, que envolvem o processo de comunicação com o lado do servidor em chamadas simples de função:

Lista 14. public/javascripts/services.js
        angular.module('pollServices', ['ngResource']).
factory('Poll', function($resource) {
            return $resource('polls/:pollId', {}, {
              query: { method: 'GET', params: { pollId: 'polls' }, isArray: true }
            })
          });

Após criar o arquivo, é necessário incluí-lo no modelo index.jade. Inclua esta linha no último elemento de script na seção de cabeçalho:
script(src='/javascripts/services.js').

Também é necessário informar ao aplicativo Angular para usar esse módulo de serviço. Para fazer isso, abra public/javascripts/app.js e altere a primeira linha para este código:
angular.module('polls', ['pollServices']).

Por fim, altere os controladores Angular para que usem o serviço para consultar e armazenar pesquisas no banco de dados. No arquivo public/javascripts/controllers.js, altere PollListCtrl para: .

Lista 15. public/javascripts/controller.js
        function PollListCtrl($scope, Poll) {
          $scope.polls = Poll.query();
        }
   ...

Atualize o comando PollItemCtrl para consultar uma pesquisa por seu ID:

Lista 16. public/javascripts/controller.js (continuação)
...
        function PollItemCtrl($scope, $routeParams, Poll) {
          $scope.poll = Poll.get({pollId: $routeParams.pollId});
          $scope.vote = function() {};
        }
 ...

De forma semelhante, altere a função PollNewCtrl para que ela envie os novos dados da pesquisa para o servidor quando o formulário for enviado.

Lista 17. public/javascripts/controller.js (continuação)
...
        function PollNewCtrl($scope, $location, Poll) {
          $scope.poll = {
            question: '',
            choices: [ { text: '' }, { text: '' }, { text: '' }]
          };
           $scope.addChoice = function() {
            $scope.poll.choices.push({ text: '' });
          };
          $scope.createPoll = function() {
            var poll = $scope.poll;
            if(poll.question.length > 0) {
              var choiceCount = 0;
              for(var i = 0, ln = poll.choices.length; i < ln; i++) {
                var choice = poll.choices[i];
                if(choice.text.length > 0) {
                  choiceCount++
                }
              }
              if(choiceCount > 1) {
                var newPoll = new Poll(poll);
                newPoll.$save(function(p, resp) {
                  if(!p.error) {
                    $location.path('polls');
                  } else {
                    alert('Could not create poll');
                  }
                });
              } else {
                alert('You must enter at least two choices');
              }
            } else {
              alert('You must enter a question');
            }
          };
        }

Execute o aplicativo

 

Está quase pronto! Nesse momento, o aplicativo deve permitir que os usuários visualizem e procurem por pesquisas, criem pesquisas e visualizem as opções de votação de uma pesquisa individual. Antes de executar o aplicativo, verifique se o MongoDB está em execução localmente. Para isso, geralmente basta abrir um terminal ou prompt de comandos e executar o comando mongod. Deixe a janela do terminal aberta ao executar o aplicativo:

Figura 3. Visualizar as opções da pesquisa
Viewing a poll's choices

Após executar o aplicativo, navegue para http://localhost:3000 no navegador e crie algumas pesquisas. Ao clicar em uma pesquisa, é possível ver as opções disponíveis, mas ainda não será possível votar na pesquisa nem ver os resultados. Iremos tratar disso na próxima e última etapa.

Etapa 4.Votação em tempo real com o Socket.io

 


Os Web Sockets permitem que o lado do servidor se comunique diretamente com o lado do cliente e envie mensagens a ele.

O único recurso que resta desenvolver é a funcionalidade da votação. O aplicativo permite que os usuários votem, e os resultados são atualizados em tempo real em qualquer cliente conectado. Isso é facilmente implementado usando o módulo npm de socket.io, então vamos fazer isso.

Abra o arquivo package.json na raiz do diretório do aplicativo e inclua a seguinte seção de dependências:
"socket.io": "~0.9.16".

Salve o arquivo, clique com o botão direito em Package Explorer e selecione Run As > npm install para instalar o módulo npm.

Em seguida, abra o arquivo app.js na raiz do aplicativo e remova o bloco server.listen... no final do arquivo, substituindo-o por este:

Lista 18. app.js
...
        var server = http.createServer(app);
        var io = require('socket.io').listen(server);

                io.sockets.on('connection', routes.vote);

server.listen(app.get('port'), function(){
          console.log('Express server listening on port ' +  app.get('port'));
        });

Em seguida, modifique o modelo index.jade para incluir a biblioteca de cliente socket.io. Ao executar o aplicativo, a biblioteca será disponibilizada automaticamente no local especificado, para que você não precise localizar o arquivo. Inclua logo após a linha que você incluiu na biblioteca de recursos do Angular no modelo:
script(src='/socket.io/socket.io.js').

Por fim, é necessário criar a função de voto para que um novo voto seja armazenado quando o usuário envia uma mensagem ao socket.io, de modo que uma mensagem seja, então, enviada a todos os clientes com os resultados atualizados. Inclua isso ao final do arquivo index.js no diretório routes:

Lista 19. routes/index.js
        // Socket API for saving a vote
        exports.vote = function(socket) {
          socket.on('send:vote', function(data) {
            var ip = socket.handshake.headers['x-forwarded-for'] ||
socket.handshake.address.address;
            Poll.findById(data.poll_id, function(err, poll) {
              var choice = poll.choices.id(data.choice);
              choice.votes.push({ ip: ip });
              poll.save(function(err, doc) {
                var theDoc = {
                  question: doc.question, _id: doc._id, choices: doc.choices,
                  userVoted: false, totalVotes: 0
                };
                for(var i = 0, ln = doc.choices.length; i < ln; i++) {
                  var choice = doc.choices[i];
                  for(var j = 0, jLn = choice.votes.length; j < jLn; j++) {
                    var vote = choice.votes[j];
                    theDoc.totalVotes++;
                    theDoc.ip = ip;
                    if(vote.ip === ip) {
                      theDoc.userVoted = true;
                      theDoc.userChoice = { _id: choice._id, text: choice.text };
                    }
                  }
                }
                socket.emit('myvote', theDoc);
                socket.broadcast.emit('vote', theDoc);
              });
            });
          });
        };

Observação: se você está se perguntando porque o aplicativo procura o cabeçalho 'x-forwarded-for' antes da propriedade de endereço IP regular, a resposta é: para garantir que o IP correto do cliente seja usado quando o aplicativo for implementado em um ambiente de balanceamento de carga. Se você implementar o aplicativo no Bluemix ou Cloud Foundry, por exemplo, isso é essencial para que o aplicativo funcione corretamente.

Incluir um serviço Angular para Web Sockets

 

A funcionalidade de backend para Web Sockets está completa. Tudo que falta é finalizar o frontend para enviar e receber eventos de soquete. A melhor abordagem para isso é incluir um novo serviço Angular. Substitua o conteúdo do arquivo services.js na pasta public/javascripts por este código:

Lista 20. public/javascripts/services.js
        angular.module('pollServices', ['ngResource']).
factory('Poll', function($resource) {
            return $resource('polls/:pollId', {}, {
              query: { method: 'GET', params: { pollId: 'polls' },
isArray: true }
            })
          }).
          factory('socket', function($rootScope) {
            var socket = io.connect();
            return {
              on: function (eventName, callback) {
                socket.on(eventName, function () {
                  var args = arguments;
                  $rootScope.$apply(function () {
                    callback.apply(socket, args);
                  });
                });
              },
              emit: function (eventName, data, callback) {
                socket.emit(eventName, data, function () {
                  var args = arguments;
                  $rootScope.$apply(function () {
                    if (callback) {
                      callback.apply(socket, args);
                    }
                  });
                })
              }
            };
          });

Por fim, é necessário editar o controlador PollItemCtrl para que ele receba e emita mensagens Web Socket para os votos. Substitua o controlador original por isto:

Lista 21. public/javascripts/controllers.js
...
        function PollItemCtrl($scope, $routeParams, socket, Poll) {
          $scope.poll = Poll.get({pollId: $routeParams.pollId});
          socket.on('myvote', function(data) {
            console.dir(data);
            if(data._id === $routeParams.pollId) {
              $scope.poll = data;
            }
          });
          socket.on('vote', function(data) {
            console.dir(data);
            if(data._id === $routeParams.pollId) {
              $scope.poll.choices = data.choices;
              $scope.poll.totalVotes = data.totalVotes;
            }
          });
          $scope.vote = function() {
            var pollId = $scope.poll._id,
                choiceId = $scope.poll.userVote;
            if(choiceId) {
              var voteObj = { poll_id: pollId, choice: choiceId };
              socket.emit('send:vote', voteObj);
            } else {
              alert('You must select an option to vote for');
            }
          };
        }
   ...

Visualize o produto final em ação

 

O aplicativo de pesquisas está completo. Com o mongod ainda em execução, execute o aplicativo Node novamente no Eclipse. No navegador, abra http://localhost:3000, abra uma pesquisa e vote. O resultado deve aparecer. Para ver as atualizações em tempo real, localize o endereço IP local e substitua localhost por ele. Em seguida, acesse usando uma máquina diferente, ou mesmo um smartphone ou tablet na rede local. Quando você vota em outro dispositivo, o resultado também é mostrado aqui e será enviado por push ao navegador do seu computador principal automaticamente:

Figura 4. Visualizar resultados da pesquisa
Viewing poll results

Próximas etapas: mais desenvolvimento e implementação

 

O aplicativo de pesquisa recém-criado é um bom ponto de partida, mas há outros aspectos que podem ser melhorados. Ao planejar aplicativos como esse, eu gosto de seguir uma metodologia agile, definindo histórias de usuários e épicos e dividindo o projeto em sprints. Usei o DevOps Services para este projeto, o que simplifica muito o desenvolvimento por manter todo o material paralelo e código-fonte do projeto em um repositório na nuvem.

Leia:Início do projeto no DevOps Services

Quando estiver satisfeito com o aplicativo, a próxima etapa será compartilhar com o mundo. Anteriormente, implementar até mesmo um aplicativo simples poderia ser um pesadelo, mas, felizmente, esses dias acabaram. Usando a plataforma Bluemix compatível com o Cloud Foundry da IBM, é possível implementar seus aplicativos na nuvem em minutos com o mínimo de configuração e ainda menos confusão.

Conclusão

 

É uma época maravilhosa para ser desenvolvedor. Temos a nossa disposição diversas estruturas e ferramentas que fazem o desenvolvimento de ótimos aplicativos não só mais simples e mais rápido, mas também mais prazeroso. Neste artigo, você aprendeu como desenvolver um aplicativo usando o que chamamos de pilha MEAN (Mongo, Express, Angular, Node). Essa pilha pode um dia substituir a pilha LAMP (Linux, Apache, MySQL, PHP), que é sinônimo de simplicidade em relação ao desenvolvimento e à implementação de aplicativos da web. Eu, pelo menos, mal posso esperar.


Temas relacionados:Node.jsMongoDBJavaScript

Incluir um comentário

Observação: elementos HTML não são suportados nos comentários.


1000 caracteres restantes

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre, Cloud computing
ArticleID=977881
ArticleTitle= Desenvolva um aplicativo de pesquisas em tempo real com Node.js, Express, AngularJS e MongoDB
publish-date=12052014