Cargando



Crear rutas dinamicas con ngRoute de AngularJS

Aprende con este tutorial a crear un proyecto completo con rutas dinámicas ngRoute en AngularJS


may 18 2016 10:14
Profesional

angular-js-solvetic.jpg

 

Nota
Para la realización de este tutorial es recomendable tener bases claras sobre AngularJS, ya que no entraremos en detalle sobre algunos aspectos técnicos de esta tecnología.

 

Si bien sabemos, AngularJS nos provee gran cantidad de módulos, servicios y filtros que nos vienen de maravilla a la hora de crear una aplicación web o móvil para la actualidad. Hay otros módulos que no encontramos en el core de este framework, uno de estos es ngRoute. Este módulo tiene como función usar URLs amigables asignándole un controlador y un template el cual es llamado automáticamente via Ajax.

 

Mayor información sobre ngRoute:

 

 

Uso de ngRoute

 

Primero creamos nuestro directorio de proyecto, lo llamaremos routeapp, dentro de este directorio creamos otro llamado public, en public creamos un archivo index.html. Ahora, dentro de public creamos un directorio llamado js donde vamos a colocar nuestros archivo de angular. Dentro de js empezamos colocamos dos primeros archivos llamados app.js y controller.js

 

Podemos conseguir todas las versiones actuales de angularjs en en este enlace: https://code.angularjs.org/. Para usar el tutorial usaremos la versión 1.5.5 https://code.angularjs.org/1.5.5/
Código index.html

<!DOCTYPE html>
<html lang="en" ng-app="routeapp" ng-controller="MainController">
<head>
  <meta charset="UTF-8">
  <title>Ng Route Dinámico</title>
</head>
<body>
  <script src="https://code.angularjs.org/1.5.5/angular.min.js"></script>
  <script src="https://code.angularjs.org/1.5.5/angular-route.min.js"></script>
  <script src="js/controller.js"></script>
  <script src="js/app.js"></script>
</body>
</html>
Código app.js
angular.module('routeapp', ['ngRoute', 'routeapp.controller'])
;
Código controller.js
angular.module('routeapp.controller', [])
.controller('MainController', function(){
  console.log('AngularJS');
})
;
Ahora ejecutamos esto en un servidor web. Pueden usar el que ustedes gusten, ya sea Apache, nginx, Tomcat, etc. Para mi caso usaré express de nodejs. Si deseas también hacerlo con nodejs puedes seguir los siguientes pasos. Si nunca has usado nodejs puedes seguir el siguiente tutorial donde se explica:

 

Usamos el siguiente comando en la raíz del proyecto desde la línea de comandos.

npm ini
npm install --save-dev express
Después de la instalación de express creamos un archivo en la raíz del proyecto llamado server.js y le agregamos el siguiente código:
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:
node server.js
para iniciar el servidor web.

 

Cuando inicies el servidor web verifica que la consola del inspeccionador de elementos de tu navegador haya escrito la palabra AngularJS.

 

rutas-dinamicas-Ngroute-AngularJS-1.jpg

 

rutas-dinamicas-Ngroute-AngularJS-2.jpg

 

rutas-dinamicas-Ngroute-AngularJS-3.jpg

 

Ahora vamos a hacer el uso de ngRoute.

 

Utilizando rutas


Vamos a utilizar la función config de angular para crear las rutas de nuestra webapp.
.config(function($routeProvider){
$routeProvider
.when('/home', {  templateUrl: 'tpl/home.html',  controller: 'HomeController' } )
.otherwise({redirectTo: '/home'});
})
Código app.js
  • /home: el URI para nuestra página de inicio.
  • templateURL: la ruta de nuestra plantilla para el home.
  • controller: El controlador asignado para la plantilla home.
  • Otherwise: Coloca por defecto nuestra web en /home
Creamos un nuevo directorio dentro de public llamado tpl, y dentro de tpl creamos un archivo llamado home.html.
<h1>Bienvenidos a mi aplicación</h1>
Dentro del body de index.html agregamos una etiqueta div con el atributo ng-view quién se encargará de renderizar el template home.html y las futuras plantillas que vamos a ir creando en el tutorial.

 

Información acerca de ngView:

 

 

Código en index.html:

<div ng-view></div>
Agregamos el controlador de home en controller.js
.controller('HomeController', function(){
  console.log('HomeController');
})
Si todo salió correctamente debe salirte algo como la siguiente imagen:

 

rutas-dinamicas-Ngroute-AngularJS-4.jpg

 

Persistencia de datos


Ya probamos que nuestro servicio de rutas está funcionando correctamente, seguimos con crear un módulo para manejar los usuarios, en dicho módulo podremos crear, listar, editar y eliminar usuarios. Para el tutorial no necesitamos comunicarnos con un backend, lo cual haremos la persistencia de datos con un array, lo cual quiere decir que estos datos son temporales y que cada vez que refresquemos la aplicación se perderán dichos datos.

 

Empezamos creando los siguientes archivos services.js y values.js dentro del directorio js

angular.module('routeapp.values', [])
.value('Users', [])
;
Código de values.js
angular.module('routeapp.services', ['routeapp.values'])
.factory('Databases', ['Users', function(Users){
  return{
    DataUser: {
	  add : function(user){
	    Users.push(user);
	  },
	  list : function(){
	    return Users;
	  },
	 
	  update : function(index, user){
	    return Users[index] = user;
	  },
	  get : function(index){
	    return Users[index];
	  },
	 
	  destroy : function(index){
	    return Users.splice(index, 1);
	  }
    }
  };
}])
 
.factory('Util', [function(){
  return {
    clone: 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;
    }
  }
}])
;
Código services.js

 

En services js creamos dos factory llamados Databases y Util.

  • Databases: Se encargará de la persistencia de los datos de los registros de usuario (usando las funciones add, update, list, get, destroy).
  • Util: Nos servirá como clonador de los datos que vamos a necesitar cuando registremos un usuario.

 

Inyectamos el módulo services a nuestro app.js

routeapp.services
El código de la primera linea de app.js quedaría así:
angular.module('routeapp', ['ngRoute', 'routeapp.controller', 'routeapp.services'])
Ahora solo nos queda guardar en index.html los script de services.js y values.js, colocarlos antes del script app.js para evitar cualquier tipo de inconveniente en la ejecución de la aplicación.
<script src="js/controller.js"></script>
<script src="js/values.js"></script>
Antes de continuar probemos que nuestra aplicación no esté presentando errores en la consola de desarrollo. AsÍ van los archivos creados hasta el momento.

 

rutas-dinamicas-Ngroute-AngularJS-5.jpg

 

Proseguimos creando las plantillas para el registro y listado de usuarios. Creamos dentro de tpl a user.html y user-list.html

<form>
 
  <div>
    <label for="username"> Nombre de usuario
	  <input type="text" ng-model="user.username">
    </label>
   
    <label for="name"> Nombre
	  <input type="text" ng-model="user.name">
    </label>
   
    <label for="email"> Correo
	  <input type="text" ng-model="user.email">
    </label>
   
    <button ng-click="save()">Guardar</button>
  </div>
</form>
Código user.html
<table>
  <tr>
    <th>Usuario</th>
    <th>Nombre</th>
    <th>Correo</th>
  </tr>
  <tr ng-repeat="item in dataUser" >
    <td>{{item.username}}</td>
    <td>{{item.name}}</td>
    <td>{{item.email}}</td>
  </tr>
</table>

Código user-list.html

 

Dentro de controller.js agregamos el controlador para user.html y user-list.html

.controller('UserController', function($scope, Databases, Util){
  $scope.user = {};
  $scope.save = function(){
    var user = Util.clone($scope.user);
    Databases.DataUser.add(user);
    $scope.user = {};
  };
})
.controller('UserListController', function($scope, Databases){
  $scope.dataUser = Databases.DataUser.list();
})
Código controller.js

 

Agregar en index.html los enlaces para poder acceder a los dos templates:

<ul>
    <li><a href="#/user"> Registrar Usuario </a></li>
    <li><a href="#/user/list"> Consultar Usuario </a></li>
  </ul>
Añadido en index.html

 

Solo nos falta añadir a config de app.js las rutas nuevas que hemos creado, colócalas antes de la función otherwise:

.when('/user', {  templateUrl: 'tpl/user.html',  controller: 'UserController' } )
.when('/user/list', {  templateUrl: 'tpl/user-list.html',  controller: 'UserListController' } )
Veamos como va todo hasta ahora.

 

rutas-dinamicas-Ngroute-AngularJS-6.jpg

 

 

rutas-dinamicas-Ngroute-AngularJS-8.jpg

 

Prueba registrando varios usuarios y verificando que se están registrando correctamente desde Consultar Usuarios.

 

rutas-dinamicas-Ngroute-AngularJS-9.jpg

 

rutas-dinamicas-Ngroute-AngularJS-10.jpg

 

Listo, ahora seguimos con la actualización y eliminación de usuarios. Para actualizar un usuario solo basta agregar nueva funcionalidad a UserController, cambiamos el anterior código por este nuevo:

.controller('UserController', function($scope, Databases, Util, $routeParams, $location){
  var userID  = $routeParams.userID;
  var isEdit = (userID != undefined);
  $scope.user = {};
  if(isEdit){
    $scope.user = Databases.DataUser.get(userID);
  }
  $scope.save = function(){
    var user = Util.clone($scope.user);
    if(isEdit){
	  Databases.DataUser.update(userID, user);
	  $location.path('/user/list');
    }else{
	  Databases.DataUser.add(user);
    }
    $scope.user = {};
  };
})
Explicación del nuevo código:
  • $routeParams: Este servicio nos va a devolver los parametros GET de nuestra aplicación, en este caso lo usaremos para que nos devuelva el ID del usuario que vayamos a actualizar. $routeParams.userID. Más información acerca de $routerParams https://docs.angular...ce/$routeParams

 

También tenemos que agregar una nueva ruta en config de app.js:

.when('/user/:userID', {  templateUrl: 'tpl/user.html',  controller: 'UserController' } )
Es importante colocar esta nueva ruta debajo de la ruta '/user/list', para que nos nos vaya a presentar conflicto con esta última mencionada.
  • '/user/:userID': Como podemos ver está URL tiene algo especial llamado :userID, esta es el parámetro que usaremos en UserController.

 

Falta solo agregar una nueva columna en user-list.html donde agregaremos un enlace a editar el usuario registrado.

<td><a href="#/user/{{$index}}">Editar</a></td>
Código en user-list.html

 

Ahora solo nos queda probar este nuevo funcionamiento, refresca la aplicación, registra y luego edita el usuario.

 

rutas-dinamicas-Ngroute-AngularJS-11.jpg

 

rutas-dinamicas-Ngroute-AngularJS-12.jpg

 

rutas-dinamicas-Ngroute-AngularJS-13.jpg

 

rutas-dinamicas-Ngroute-AngularJS-14.jpg

 

rutas-dinamicas-Ngroute-AngularJS-15.jpg

 

Solo nos falta agregar la funcionalidad de eliminar los usuarios. Creamos una nueva plantilla en tpl llamado user-delete.html

<h1>Eliminar Usuario</h1>
<div>Desea eliminar a <strong>{{user.name}}</strong>?</div>
<button ng-click="destroy();">Eliminar</button>
Código de user-delete.html

 

Agregamos un nuevo enlace en la tabla user-list.html para poder acceder al template user-delete.html

<td><a href="#/user/delete/{{$index}}">Eliminar</a></td>
Agregamos en controller.js el controlador para user-delete.html llamado UserDeleteController
.controller('UserDeleteController', function($scope, Databases, $routeParams, $location){
  var userID = $routeParams.userID;
  $scope.user = Databases.DataUser.get(userID);
  $scope.destroy = function(){
    Databases.DataUser.destroy(userID);
    $location.path('/user/list');
  }
})
Y Agregamos la ruta en config de app.js
.when('/user/delete/:userID', {  templateUrl: 'tpl/user-delete.html',  controller: 'UserDeleteController' } )
Refrescamos la aplicación, registramos y luego probamos el funcionamiento de eliminar el usuario.

 

rutas-dinamicas-Ngroute-AngularJS-16.jpg

 

rutas-dinamicas-Ngroute-AngularJS-17.jpg

 

rutas-dinamicas-Ngroute-AngularJS-18.jpg

 

Hemos terminado nuestra aplicación base!. Ya dominamos la creación de rutas manuales en nuestra aplicación, pero si nos ponemos a ver detenidamente y vemos cuáles son las rutas construidas:

  • /home
  • /user
  • /user/list
  • /user/:userID
  • /user/delete/:userID
Hemos creado para el módulo de persistencia de usuarios 4 rutas más la del home. Si tuviéramos que crear otros módulos de persistencia a nuestra aplicación, como Productos, Clientes, Ventas, etc. Tendríamos que crear 12 rutas más. Lo cual haría crecer nuestro archivo de app.js cada vez que agreguemos nuevas rutas. Para evitar esto, vamos a crear un generador de rutas dinámicas para evitar este dolor de cabeza.

 

Cómo crear rutas dinámicas


Analicemos fijamente nuestras rutas actuales, para crear un nuevo usuario usamos la ruta /user.
  • Para consultar los usuarios /user/list
  • Para editarlo /user/:userID
  • Para eliminar /user/delete/:userID.

 

Podemos crearnos unas rutas donde solo se usen uno, dos o tres parámetros y estos capturarlos, usarlos a nuestro gusto. Quedaría de esta forma:

 

Hay que dejar algo claro, para que nos funcione correctamente las rutas dinámicas necesitamos seguir las siguientes reglas, para explicarlas usaremos el mismo ejemplo de user:

 

1. El nombre user debe ser usado tanto como prefijo de la plantilla como del controlador.


2. Para las consultas como segundo prefijo en el tutorial usamos la palabra list, de igual forma puedes cambiarla por el que quieras pero la palabra que uses debes tenerla tanto en el nombre de la plantilla como en el nombre del controlador. Ej: user-list.html y UserListController; para delete: user-delete.html y UserDeleteController


3. Para que se puedan identificar los prefijos en los controladores usar mayúsculas.


4. Los nombres de los controladores siempre deben finalizar con la palabra Controller.

var route  = {
	  controller: 'RouteController',
	  templateUrl: function(uri){
	    var pattern = new RegExp("[0-9]+");
	    var part_uri = ( !pattern.test( uri.param2 ) &&  typeof uri.param2 !== 'undefined') ? '-' + uri.param2 : '';
	    return 'tpl/' + uri.param1 + part_uri + '.html';
	  }
    };
    $routeProvider
.when('/:param1', route )
    .when('/:param1/:param2', route)
    .when('/:param1/:param2/:param3', route )
    .otherwise({redirectTo: '/home'});
Código en app.js

 

Creamos tres patrones de rutas, para cuando sólo tenga un solo parámetro funcionaria para /user y /home. Para dos parametros /user/:userID y /user/list. Para tres parametros /user/delete/:userID

 

También necesitamos crear un nuevo controlador que será el encargado de guiar a los distintos controladores dependiendo de del URI.

.controller('RouteController', function($scope, $routeParams, $controller, $filter){
  var prefix = $filter('prefixController')($routeParams.param1) +''+ $filter('prefixController')($routeParams.param2);
  $controller(prefix+'Controller', {$scope: $scope});
})
Código de RouteController

 

Este controlador a su vez depende un filtro, creamos un nuevo archivo en el directorio js llamado filters.js

angular.module('routeapp.filters', [])
.filter('prefixController', function(){
  return function(text){
   
    if(typeof text === 'undefined' ){
	  return '';
    }
    var p_string = new RegExp('[a-z]+[0-9]*');
    var p_int = new RegExp("[0-9]+");
   
    if(p_int.test(text)){
	  return '';
    }else if(p_string.test(text) ){
	  return text.charAt(0).toUpperCase() + ( (text.length > 1)? text.slice(1) : '' );
    }else{
	  return '';
    }
  };
})
;
Código de filters.js

 

Inyectamos el filtro en app.js

routeapp.filters
Importamos el script filters.js a index.html colocado antes de app.js
<script src="js/filters.js"></script>
Nos falta cambiar un último detalle en UserController y UserDeleteController. Como ahora estámos usando parámetros :param1, :param2, :param3; el parámetro :userID ya no estará disponible. Lo cual nos toca cambiarlo en los controladores. Para UserController usar param2, y para UserDeleteController param3

 

Código UserController:

var userID  = $routeParams.param2;
Código UserDeleteController:
var userID  = $routeParams.param3;
Hemos finalizado nuestro enrutador dinámico. Ahora ya no tenemos que preocuparnos en crear nuevas rutas a nuestro sitio ya que todo se encuentra controlado por nuestro RouterController y la nueva configuración de del $routerProvider, puedes probarlo creando nuevas plantillas y asignarle sus rutas y controladores. Para finalizar podemos crearnos una nueva plantilla que nos puede servir para detectar cuando se intente acceder a una url que no se encuentra en nuestro sitio. Podemos usar una plantilla 404. Vamos a crearla en tpl con el nombre 404.html

 

Código para 404.html

<h1>Ups, esta sección no se encuentra disponible en nuestra aplicación.</h1>
Controlador 404Controller
.controller('404Controller', function(){
})
Para que podamos detectar cuando se está intentando acceder a una ruta no disponible podemos usar un listener de angularjs que se encarga de ello. Reemplazamos el código de MainController por el siguiente:
.controller('MainController', function($scope, $location){
  console.log('AngularJS');
  $scope.$on('$routeChangeError', function(next, current) {
	 $location.path('/404');
  });
})
Solo basta con ejecutar la aplicación y colocar una URL no disponible en nuestro sitio, por ejemplo http://localhost:300...url-desconocida. La aplicación se redireccionará inmediatamente a /404

 

rutas-dinamicas-Ngroute-AngularJS-19.jpg

 

Puedes descargar esta demo del tutorial aquí:

 

Fichero Adjunto  routeapp.zip   344,9K   334 Descargas


¿Te ayudó este Tutorial?


1 Comentarios


Jaime Martinez
sep 22 2017 20:33

Mucha gracias por este tutorial, ha sido de gran ayuda y era lo que andaba buscando... mil gracias

No esperes más y entra en Solvetic
Deja tus comentarios y aprovecha las ventajas de la cuenta de usuario ¡Únete!

X