Ver destacados

Tablas dinamicas con AngularJS

Cómo crear una tabla dinámica con este framework y manipula cualquier tipo de registros que necesites de desarrollo.
Escrito por
41.8K Visitas  |  Publicado jun 01 2016 13:29
Favorito
Compartir
Comparte esta pagina a tus Amigos y Contactos usando las siguientes Redes Sociales


Como bien sabemos, AngularJS nos provee una gran cantidad de utilidades interesantes a la hora de trabajar desarrollo web y móvil, es tantas las ventajas que nos ayuda a generar gran dinamismo en nuestros proyectos web.

 

Hoy aprenderás a crear una tabla dinámica con este framework con la que podrás manipular cualquier tipo de registros que tengas en tu desarrollo, ya basta de trabajar módulos por separados dependiendo de la información que estes manejando, todo esto lo puedes trabajar desde algo que se codifique una sola vez. Con ella podrás listar, filtrar, paginar, ordenar, crear, editar y borrar la información que tengas guardada en el sistema. Para esta primera parte trabajaremos con todo lo concerniente a consultas (listar, filtrar, paginar, ordenar), en la segunda parte trabajaremos con la creación edición y eliminación de registros.

 

En su día ya hicimos un tutorial de crear rutas inámicas con Ngroute de AngularJS. Hoy entramos de lleno en ello de otras forma. También cabe aclarar que es recomendable tener conocimientos de AngularJS, ya que no se explicará a fondo algunos detalles de este framework, también es recomendable (no obligatorio) tener instalado GIT, NPM en nuestro sistema ya que trabajaremos con ellos en este tutorial.

 

Creando Proyecto


Primero organicemos nuestro proyecto con npm, git y bower. Crea el directorio del proyecto llamado table-angular, luego dentro del proyecto usar el comando `git init` para crear el repositorio y luego usar el comando `npm init` para crear el archivo package.json.

 

Instalamos nuestro servidor web con el comando `npm install --save-dev express`. Después de la instalación creamos un archivo llamado server.js

var express = require('express');
var app = express();
var port = Number(process.env.PORT || 3000);
app.use(express.static(__dirname + '/public'));
app.listen(port, function() {
    console.log('App iniciada en http://localhost:' + port);
});
Ahora ejecutamos el comando (Para instalar bower):
npm install --save-dev bower
Dentro del directorio raíz creamos otro llamado public, en public creamos un archivo index.html. Luego creamos un directorio dentro de public llamado assets, dentro de este directorio creamos otro llamado js, y en él crearemos los archivos app.js, controller.js, services.js y filters.js. Luego creamos un directorio llamado css y dentro de este creamos un archivo llamado main.css

 

Hasta ahora nuestro proyecto va de la siguiente forma:

 

 

 

 

Seguimos con nuestras librerías a usar. Usaremos bower para este caso, usaremos las librerías de angular, y foundation para darle un poco de estilo a nuestra vista. También anexaremos una librería llamada angular-utils-pagination, la cual nos dará funcionalidad con la paginación en nuestro proyecto. Antes de instalar estas librerías crearemos un archivo en nuestro directorio raíz llamado .bowerrc el cual se encarga de indicarle a bower donde guardar dichas librerías.

 

Más información de cada una de las librerías que vamos a usar:

 

 Foundation

 Angular pagination

 

Código .bowerrc

{
  "directory": "public/assets/bower_components"
}
Para instalar las librerías usaremos los comandos:
  • `bower install --save angular`
  • `bower install --save foundation`
  • `bower install --save angular-utils-pagination`

 

Cabe aclarar que foundation trabaja con jquery y se descargan cuando usamos bower, pero para nuestro proyecto no las usaremos, lo cual podemos omitirlas, en mi caso las eliminaré del directorio de bower_components.

 

Esto es lo que llevamos creado hasta ahora:

 

 

 

 

Pasamos ahora codificar la tabla dinámica 😁, empezamos con index.html, anexamos todas las librerías que necesitamos.

<!DOCTYPE html>
<html lang="es" ng-app="table" ng-controller="TableController">
<head>
<meta charset="UTF-8">
<title>Tabla Dinamica con Angular JS</title>
<link rel="stylesheet" href="assets/bower_components/foundation/css/foundation.min.css">
<link rel="stylesheet" href="assets/bower_components/foundation/css/normalize.min.css">
<link rel="stylesheet" href="assets/css/main.css">
</head>
<body>
<script src="assets/bower_components/angular/angular.min.js"></script>
<script src="assets/bower_components/angularUtils-pagination/dirPagination.js"></script>
<script src="assets/js/app.js"></script>
<script src="assets/js/controller.js"></script>
<script src="assets/js/filters.js"></script>
<script src="assets/js/services.js"></script>
</body>
</html>
En controller.js creamos un controlador llamado TableController que será llamado desde index.html

 

Código de controller.js

angular.module('table.controller', [])
.controller('TableController',function(){
console.log('Table Controller');
})
;
Para filter.js solamente creamos la instancia del módulo, por ahora:
angular.module('table.filters', []);
Lo mismo hacemos con services.js, solo creamos la instancia:
angular.module('table.services', []);
Por último llamamos todos los módulos desde app.js.
angular.module('table', ['angularUtils.directives.dirPagination', 'table.controller', 'table.services', 'table.filters']);
Y con esto podremos hacer la primera ejecución de nuestra aplicación usando el comando:
`node server.js`
Si usamos la herramienta de desarrollador del navegador en la pestaña consola podemos verificar que se haya impreso la palabra Table Controller para indicar que todo lo que hemos creado hasta ahora este funcionando correctamente.

 

 

 

 

 

 

 

Agregando servicios


Empezaremos creando nuestros servicios que vamos a utilizar. Para el tutorial no vamos a conectarnos a ningun servidor remoto, por lo cual optaremos por guardar los registros en nuestros archivos de javascript. Usaremos tres tipos de registros. Juegos, Artículos y Usuarios lo cual no comparten los mismos campos, cada uno simulará un servicio independiente como si viniera de un API REST, todos en formato JSON. Si quieres puedes agregar otros campos a estos tres tipos o agregar uno nuevo.
Código services.js
.factory('Users', function(){
return{
  get : function(){
   var data = [ {id: 1, nombre: 'Juan', apellido: 'Perez'},
	  {id: 5, nombre: 'Ana María', apellido: 'Garcia'},
	  {id: 15, nombre: 'Alejandro', apellido: 'Magno'},
	  {id: 18, nombre: 'Andrea', apellido: 'L'},
	  {id: 19, nombre: 'Pablo', apellido: 'Gutierrez'},
	  {id: 8, nombre: 'Ana', apellido: 'H'},
	 ];
   return data;
  }
 
}
})
.factory('Articles', function(){
return{
  get : function(){
   var data = [
    { id: 20, titulo: 'Mi primer articulo', resumen: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' },
    { id: 21, titulo: 'Mi segundo articulo', resumen: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' },
    { id: 22, titulo: 'Mi tercer articulo', resumen: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' }
   ];
   return data;
  }
}
})
.factory('Games', function(){
return{
  get : function(){
   var data = [
    {id: 1, titulo: 'Metroid', genero: 'Acción'},
    {id: 2, titulo: 'Zelda', genero: 'Aventura'},
    {id: 3, titulo: 'Golden Eye', genero: 'Shooter'},
    {id: 4, titulo: 'Fifa 2016', genero: 'Deportes'},
   ];
   return data;
  }
}
})
También anexaremos otro servicio llamado Call el cual se encargará de llamar a los distintos datos (Usuarios, Juegos y Artículos).
.factory('Call', function($injector){
return {
  get : function(type){
   var service = $injector.get(type);
   return service.get();
  }
};
})
Y por último crearemos un servicio llamado Persistence que se encargará de hacer el CRUD de nuestra información. Como ya lo había dicho al principio, solo haremos funciones de consulta en esta primera parte del tutorial, asi que solo solo será usado la función list, en la segunda parte usaremos el resto.
.factory('Persistence', function(Call){
  return{
	  add : function(type, data){
	    var Obj = Call.get(type);
	    Obj.push(data);
	  },
	  list : function(type){
	    return Call.get(type);
	  },
	 
	  update : function(type, index, data){
	   var Obj = Call.get(type);
	    return Obj[index] = data;
	  },
	  get : function(type, index){
	   var Obj = Call.get(type);
	    return Obj[index];
	  },
	 
	  destroy : function(type, index){
	   var Obj = Call.get(type);
	    return Obj.splice(index, 1);
	  }
  };
})
Necesitamos agregar un servicio que se encargará de manipular todos los objetos de la tabla dinámica.
.factory('ObjectService', function(){
return {
  getPropertiesObject: function(object){
   var properties = [];
   for( var property in object){
    properties.push(property);
   }
   return properties;
	 },
	 cloneObject: function (obj) {
   if (null === obj || "object" !== typeof obj) {
    return obj;
   }
   var copy = obj.constructor();
   for (var attr in obj) {
    if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
   }
   return copy;
	 },
  createParamObject: function(obj, parameter, value){
   return Object.defineProperty(obj, parameter, {value: value, writable : true, configurable: true, enumerable : true } );
  },
}
})
Agregando servicio

 

 

Creando Controlador

angular.module('table.controller', [])
.controller('TableController',function($scope, $filter, ObjectService, Persistence){
 
  ITEM_PER_PAGE = 5;
  $scope.types = [{value: 'Users', label:'Usuarios'}, {value: 'Articles', label:'Articulos'}, {value: 'Games', label:'Juegos'} ];
  $scope.data = [];
  $scope.head = [];

  //Data Type
  $scope.changeData = function (){
   $scope.uri = $scope.type.value;
   $scope.data = Persistence.list($scope.type.value);
   $scope.head = ObjectService.getPropertiesObject($scope.data[0]);
   $scope.propertiesHead = $scope.head;
   $scope.filter = $filter('fieldsSelectFilter')( [ObjectService.cloneObject($scope.propertiesHead), ObjectService.cloneObject($scope.head)] );;
   $scope.selectFilter = '$';
   $scope.changeFilterTo();
  };
  //Filter
  $scope.changeFilterTo = function(){
    $scope.search = ObjectService.createParamObject({}, $scope.selectFilter, '');
  };
 
 
  //***** by
  $scope.orderBy = {pedicate: 'name', reverse: false};
  $scope.***** = function(predicate) {
    $scope.orderBy.reverse = !$scope.orderBy.reverse;
    $scope.orderBy.predicate = predicate;
  };
 
  //Pagination
  $scope.limit = {per_page: ITEM_PER_PAGE};

  //Default
  $scope.type = $scope.types[0];
  $scope.changeData();
})
;
Expliquemos un poco el código que acabamos de agregar:
  • ITEM_PER_PAGE: Se encargará de manejar el límite de los registros a mostrar por página, en este caso hemos indicado que son 5 por página, cuando haya mas de 5 registros aparecerá un paginador para ir desplazandonos, ya queda a tu gusto colocar cuantos quieres visualizar al tiempo.
  • $scope.types: Contiene un array con los datos de cada tipo de datos que manipularemos en la tabla, trabaja en conjunto con changeData.
  • $scope.data: Será el encargado de manipular la información que tenga asignada en su momento y ser renderizada en la tabla dinámica.
  • $scope.head: Será el encabezado de la tabla.

 

Funciones:

  • $scope.changeData: Se encargará de cambiar los datos que tengamos en el momento en la tabla.
  • $scope.changeFilterTo: Tendrá como funcionalidad poner un tipo de filtro específico a la hora de filtrar la información. Por ejemplo: Los registros de usuario los tipos de filtro serían nombre y apellido.
  • $scope.*****: Usado para organizar los datos por las columnas de las tablas. Esta función será asignada a la cabecera de las columnas.

 

Código index.html

<div class="row">
  <div class="columns">
   Datos
   <select ng-options="item as item.label for item in types"
    ng-model="type" ng-change="changeData()"></select>
  </div>
 
</div>
<div class="row">
  <div class="columns small-6">
   <label for="">Filtrar
    <input type="text" ng-model="search[selectFilter]" >
   </label>
  </div>
  <div class="columns small-6">
   <label for="">Filtrar por</label>
   <select ng-model="selectFilter" ng-init="selectFilter='$'" ng-change="changeFilterTo();">
    <option ng-repeat="item in filter[0]" value="{{item}}">
	 {{filter[1][$index]}}
    </option>
   </select>
  </div>
</div>
<div class="row">
  <div class="columns">
   <table>
    <tr ng-if="data.length > 0">
	 <th>Acciones</th>
	 <th class="*****" ng-repeat="item in head" ng-click="*****(propertiesHead[$index])" >
	  {{item}}
	  <i ng-show="orderBy.predicate==propertiesHead[$index]" ng-class="{'up':orderBy.reverse,'down':!orderBy.reverse}"></i>
	 </th>
    </tr>
    <tr ng-if="data.length > 0" dir-paginate="col in data | orderBy : orderBy.predicate : orderBy.reverse | filter : search | itemsPerPage : limit.per_page">
	 <td>
	  <a href="#/{{uri}}/{{col.id}}">Editar</a>
	  <a href="#/{{uri}}/delete/{{col.id}}">Eliminar</a>
	 </td>
	 <td ng-repeat="item in col">{{item}}</td>
    </tr>
   </table>
  </div>
</div>
<div class="row">
<div class="columns">
<dir-pagination-controls max-size="5" direction-links="true" boundary-links="true"></dir-pagination-controls>
</div>
</div>
Agregamos un filtro que lo que hará es anexar un nuevo campo al selector de tipos de filtros, este campo será para aplicar filtro a cualquier columna de nuestra tabla, en resumen utiliza el espacio donde se encuentra el campo ID y se asigna esta nueva propiedad.

 

Código filters.js

.filter('fieldsSelectFilter', function(){
  return function(data){
    data[0][0] = '$';
    data[1][0] = 'Todos';
    return data;
  };
})
Agregamos nuestro código CSS para darle un poco de estilos a las columnas de las tablas, y al paginador. Hay que destacar algo interesante en el CSS, vamos a ocultar la columna de id de los registros ya que esto no es importante visualizarlo al usuario. A las columnas les agregaremos “iconos” que nos indicarán cuando la columna esté ordenando la información de forma ascendente o descendente.

 

Código main.css

select option { text-transform: capitalize; }
ul.pagination{ width: 25%; margin: 0 auto; }
table{ width:100%; }
table tr th { text-transform: capitalize; }
table tr th:nth-child(1){ width: 150px; }
table tr th:nth-child(2), table td:nth-child(2){ display: none;  }
th.*****{ cursor: pointer; }
i.up:before, i.down:before{
content: '<';
font-style: normal;
font-size: 14px;
width: 15px;
height: 20px;
position: relative;
display: inline-block;
left: 10px;
}
i.up:before{
content: '>';
}
i.up{
  top: -5px;
  transform: rotate(90deg);
  display: inline-block;
  position: relative;
}
i.down{
transform: rotate(90deg);
display: inline-block;
top: -5px;
position: relative;
}
tr > td a{
  margin-left: 5px;
}
Refrescamos nuevamente nuestro navegador y visualizamos ahora lo siguiente:

 

 

 

[color=#a9a9a9]Pulsa imagen para ampliar[/color]

 

 

Expliquemos un poco lo que hay en la interfaz. Tenemos un selector llamado datos. Este se encargará por medio de changeData extraer la información que hemos guardado en services.js. El campo filtrar se encarga de ir mostrar la información específica que indiquemos cuando escribimos en dicho campo, y “filtrar por” se encarga de detallar por cual columna queremos filtrar, por defecto filtra por TODOS los campos, también puedes darle click a las columnas para organizarlas descendente y ascendente. Haz de tu parte las distintas pruebas. Los campos editar y eliminar no son funcionales por ahora.

 

 

 

[color=#a9a9a9]Pulsa imagen para ampliar[/color]

 

 

Reglas a tener en cuenta

Como todo hay que cumplir unas reglas estrictas para que nos pueda funcionar de la mejor forma nuestro módulo de tabla dinámica. Siempre debemos tener un campo id, aunque esto es casi obvio cuando manipulamos registros de nuestra base de datos, pero no falta que aveces se nos pueda pasar esta práctica. También que este campo se coloque de primero en cada registro del JSON.

 

Por ahora queda pendiente cómo manipular los datos que vengan de un listado. Por ejemplo, el campo género en los datos de Juegos sería en realidad id foráneos de otra tabla (cuando utilizamos el concepto entidad-relación), formato a los campos numéricos y fechas, también a crear los encabezados aparte y no depender el nombre del campo que venga directamente del registro. Todo esto los veremos en la parte 2 del tutorial cuando necesitemos hacer registros y actualización de datos. Estar atentos a las novedades.

 

Hemos finalizado nuestra primera parte de la tabla dinámica. Verás lo mucho que te va a servir en tus proyectos de Angular y no tener que está creando distintas tablas para manipular distintos datos, si no que todo lo puedes centralizar con un solo módulo.

 

Descargar demo programada
table-angular.zip   6,63MB   1696 Descargas

¿Te ayudó este Tutorial?

Ayuda a mejorar este Tutorial!
¿Quieres ayudarnos a mejorar este tutorial más? Puedes enviar tu Revisión con los cambios que considere útiles. Ya hay 0 usuario que han contribuido en este tutorial al enviar sus Revisiones. ¡Puedes ser el próximo!