CRUD con Angular, Node.js y MongoDB, parte 2

Bueno, en la última publicación vimos cómo hacer CRUD con Angular, la forma sencilla y ordenada con la que Angular nos permite trabajar por separado la lógica (Javascript) y la presentación (Html) En esta ocasión vamos a continuar con el mismo ejemplo, sólo que esta vez vamos a trabajar con base de datos.

Primero, antes de iniciar el servidor Node.js, debemos tener el servicio de MongoDB funcionando.

Los que usen Windows pueden ir a la carpeta de MongoDB:

carpeta_de_mongodb\bin

Y ejecutar el archivo mongod.exe.

mongod.exe

Luego tenemos que conectar nuestra aplicación con MongoDB mediante Mongoose. Para ello vamos a nuestro archivo app.js, y agregamos la siguiente línea, en alguna parte de nuestro código:

//Conexión a Mongoose.
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/primer_base', function(error){
   if(error){
      throw error; 
   }else{
      console.log('Conectado a MongoDB');
   }
});

Insisto, si nunca antes habías conectado Node.js a MongoDB, o no tenés instalada dicha base de datos, podés revisarlo en esta publicación que hice hace un tiempo:

https://fernando-gaitan.com.ar/introduccion-a-node-js-parte-12-conexion-con-mongodb/ 

Luego vamos a crear el esquema para guardar los documentos, que tendrán los datos de los clientes:

En el archivo node.js agregamos las siguientes líneas:

//Documentos
var ClienteSchema = mongoose.Schema({
   nombre: String,
   apellido: String,
   domicilio: String,
   telefono: String,
   email: String
});
var Cliente = mongoose.model('Cliente', ClienteSchema);

Ahora tenemos que agregar las acciones para guardar, listar, ver individualmente y eliminar clientes. Vamos a dejar la acción que creamos en la última publicación tal cual como está:

app.get('/', function(req, res){
   res.sendfile('./public/index.html');
});

Agregamos la acción para listarlos:

app.get('/listar', function(req, res){
   Cliente.find({}, function(error, clientes){
      if(error){
         res.send('Error.');
      }else{
         res.send(clientes);
      }
   })
});

Para recuperar un registro:

app.get('/recuperar', function(req, res){
   Cliente.findById(req.query._id, function(error, documento){
      if(error){
         res.send('Error.');
      }else{
         res.send(documento);
      }
   });
});

Para guardarlo (insertar o modificar):

app.post('/guardar', function(req, res){
   if(req.query._id == null){
      //Inserta
      var cliente = new Cliente({
         nombre: req.query.nombre,
         apellido: req.query.apellido,
         domicilio: req.query.domicilio,
         telefono: req.query.telefono,
         email: req.query.email
      });
      cliente.save(function(error, documento){
         if(error){
            res.send('Error.');
         }else{
            res.send(documento);
         }
      });
   }else{
      //Modifica
      Cliente.findById(req.query._id, function(error, documento){
         if(error){
            res.send('Error al intentar modificar el personaje.');
         }else{
            var cliente = documento;
            cliente.nombre = req.query.nombre,
            cliente.apellido = req.query.apellido,
            cliente.domicilio = req.query.domicilio,
            cliente.telefono = req.query.telefono,
            cliente.email = req.query.email
            cliente.save(function(error, documento){
               if(error){
                  res.send('Error.');
               }else{ 
                  res.send(documento);
               }
            });
         }
      });
   }
});

Para eliminar:

app.post('/eliminar', function(req, res){
   Cliente.remove({_id: req.query._id}, function(error){
      if(error){
         res.send('Error.');
      }else{
         res.send('Ok');
      }
   });
});

Bien, ya tenemos las acciones de nuestra aplicación que nos permitirán realizar CRUD, si no estás familiarizado con esto, te invito a ver una publicación que hice explicando CRUD:

https://fernando-gaitan.com.ar/introduccion-a-node-js-parte-13-crud-con-mongoose/

Bueno, como ya tenemos nuestra aplicación conectada a MongoDB, y nuestras acciones para realizar las distintas consultas, podemos continuar modificando el controlador con Angular, y mediante Ajax, realizar todos estos procesos desde el lado del cliente:

var aplicacion = angular.module('aplicacion', []);
aplicacion.controller('Clientes', function($scope, $http) {
   $scope._id = null;
   $scope.nombre = '';
   $scope.apellido = ''
   $scope.domicilio = '';
   $scope.telefono = '';
   $scope.email = '';
   $scope.clientes = [];
   $scope.cargarClientes = function(){
      $http({
         method: 'GET', url: '/listar'
      }).
      success(function(data) {
         if(typeof(data) == 'object'){
            $scope.clientes = data;
         }else{
            alert('Error al intentar recuperar los clientes.');
         }
      }).
      error(function() {
         alert('Error al intentar recuperar los clientes.');
      });
   };
   $scope.guardarCliente = function() {
      $http({
         method: 'POST',
         url: '/guardar',
         params: {
            nombre: $scope.nombre,
            apellido: $scope.apellido,
            domicilio: $scope.domicilio,
            telefono: $scope.telefono,
            email: $scope.email,
            _id: $scope._id
         }
      }).
      success(function(data) {
         if(typeof(data) == 'object'){
            $scope.limpiarDatos();
            $scope.cargarClientes(); 
         }else{
            alert('Error al intentar guardar el cliente.');
         }
      }).
      error(function() {
         alert('Error al intentar guardar el cliente.');
      });
   };
   $scope.recuperarCliente = function(indice) {
      $http({
         method: 'GET',
         url: '/recuperar',
         params: {
            _id: indice
         }
      }).
      success(function(data) {
         if(typeof(data) == 'object'){
            $scope._id = data._id;
            $scope.nombre = data.nombre;
            $scope.apellido = data.apellido;
            $scope.domicilio = data.domicilio;
            $scope.telefono = data.telefono;
            $scope.email = data.email;
         }else{
            alert('Error al intentar recuperar el cliente.');
         } 
      }).
      error(function() {
         alert('Error al intentar recuperar el cliente.');
      });
   };
   $scope.eliminarCliente = function(indice) {
      $http({
         method: 'POST',
         url: '/eliminar',
         params: {
            _id: indice
         }
      }).
      success(function(data) {
         if(data == 'Ok'){
            $scope.limpiarDatos();
            $scope.cargarClientes();
         }else{
            alert('Error al intentar eliminar el cliente.');
         } 
      }).
      error(function() {
         alert('Error al intentar eliminar el cliente.');
      });
   };
   $scope.limpiarDatos = function() {
      $scope._id = null;
      $scope.nombre = '';
      $scope.apellido = '';
      $scope.domicilio = '';
      $scope.telefono = '';
      $scope.email = '';
   };
});

Vamos a analizar el código:

En primer lugar hemos agregado a nuestro controlador, un parámetro opcional, que en esta ocasión hemos utilizado: $http. Éste es un objeto que nos permitirá realizar peticiones ajax.

Hemos cambiado los métodos, para adaptarlos a esta nueva versión va a comunicarse con el servidor para realizar operaciones en la base de datos. Por ejemplo el método guardarCliente():

$scope.guardarCliente = function() {
   $http({
      method: 'POST',
      url: '/guardar',
      params: {
         nombre: $scope.nombre,
         apellido: $scope.apellido,
         domicilio: $scope.domicilio,
         telefono: $scope.telefono,
         email: $scope.email,
         _id: $scope._id
      }
   }).
   success(function(data) {
      if(typeof(data) == 'object'){
         $scope.limpiarDatos();
         $scope.cargarClientes(); 
      }else{
         alert('Error al intentar guardar el cliente.');
      }
   }).
   error(function() {
      alert('Error al intentar guardar el cliente.');
   });
};

Aquí podemos ver cómo realizar una petición ajax desde angular, mediante el objeto $http. Definimos el método, en este caso por POST:

method: 'POST',

La acción donde enviamos los datos:

url: '/guardar',

Y los datos que enviamos:

params: {
   nombre: $scope.nombre,
   apellido: $scope.apellido,
   domicilio: $scope.domicilio,
   telefono: $scope.telefono,
   email: $scope.email,
   _id: $scope._id
}

Además le asignamos dos eventos, success()error(). El primero se va a disparar en el momento que el servidor le devuelva una respuesta al cliente, mientras que el segundo lo hará si hubo algún problema.

Dentro de success() podemos ver como mediante el parámetro data obtenemos la respuesta del servidor.

Lo mismo harán los demás métodos, cargarClientes()recuperarCliente()eliminarCliente(), mediante peticiones asíncronas al servidor.

En cuanto al código html, el cuál tenía este aspecto:

<!DOCTYPE html>
<html ng-app="aplicacion">
   <head>
      <meta charset="utf-8" />
      <title> Clientes </title>
      <link type="text/css" href="/stylesheets/bootstrap.min.css" rel="stylesheet" />
      <script type="text/javascript" src="/javascripts/angular.min.js"></script>
      <script type="text/javascript" src="/javascripts/script.js"></script>
   </head>
   <body>
      <div ng-controller="Clientes">
         <h1> Clientes </h1>
         <form action="javascript:void(0);">
            <div>
               <div>
                  <label> Nombre </label>
                  <input type="text" ng-model="nombre" />
               </div>
               <div> 
                  <label> Apellido </label>
                  <input type="text" ng-model="apellido" />
               </div>
               <div>
                  <label> Domicilio </label>
                  <input type="text" ng-model="domicilio" />
               </div>
            </div>
            <div>
               <div>
                  <label> Teléfono </label>
                  <input type="text" ng-model="telefono" />
               </div>
               <div>
                  <label> Email </label>
                  <input type="text" ng-model="email" />
               </div> 
            </div>
            <div>
               <div>
                  <input type="submit" value="Guardar" ng-click="guardarCliente()" />
                  <input type="button" value="Limpiar" ng-click="limpiarDatos()" />
               </div>
            </div>
         </form>
         <table>
            <thead>
               <tr>
                  <th> Nombre </th>
                  <th> Apellido </th>
                  <th> Domicilio </th>
                  <th> Teléfono </th>
                  <th> Email </th>
                  <th> </th>
                  <th> </th>
               </tr>
            </thead>
            <tbody>
               <tr ng-repeat="item in clientes">
                   <td> {{item.nombre}} </td>
                   <td> {{item.apellido}} </td>
                   <td> {{item.domicilio}} </td>
                   <td> {{item.telefono}} </td>
                   <td> {{item.email}} </td>
                   <td> <a href="javascript:void(0);" ng-click="recuperarCliente($index)"> Editar </a> </td>
                   <td> <a href="javascript:void(0);" ng-click="eliminarCliente($index)"> Eliminar </a> </td>
                 </tr>
              </tbody>
           </table>
      </div>
   </body>
</html>

Vamos a hacerle unos cambios.

Primero vamos a modificar

<div ng-controller="Clientes">

Por:

<div ng-controller="Clientes" ng-init="cargarClientes()">

La directiva ng-init, nos permitirá iniciar el controlador Clientes, con el método cargarClientes(). Luego vamos a reemplazar las líneas:

<td> <a href="javascript:void(0);" ng-click="recuperarCliente($index)"> Editar </a> </td>
<td> <a href="javascript:void(0);" ng-click="eliminarCliente($index)"> Eliminar </a> </td>

Y vamos a reemplazar el índice, ya que ahora tendremos que referirnos a cada registro por su _id, el cual se genera solo:

<td> <a href="javascript:void(0);" class="btn btn-info" ng-click="recuperarCliente(item._id)"> Editar </a> </td>
<td> <a href="javascript:void(0);" class="btn btn-danger" ng-click="eliminarCliente(item._id)"> Eliminar </a> </td>

Listo, con esto tendremos una pequeña aplicación CRUD con Angular, Node y MongoDB.

Podemos iniciar el servidor yendo a nuestro proyecto de Node.js y escribiendo en la consola:

node app.js

Algo interesante, es que estas tres tecnologías manejan un lenguaje similar, con la posibilidad de transferir y recuperar datos, por medio de Json (Bson en el caso de MongoDB) Esto nos permite trabajar con nuestra aplicación en un sólo lenguaje, sin tener que andar codificando datos ni nada.

Saludos!

Descargar ejemplo

Ver parte 1

Redes sociables