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 expressDespué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.jspara 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.
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
<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:
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.servicesEl 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.
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.
Prueba registrando varios usuarios y verificando que se están registrando correctamente desde Consultar Usuarios.
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.
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.
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
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.filtersImportamos 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
Puedes descargar esta demo del tutorial aquí:
routeapp.zip 344,9K 352 Descargas
Mucha gracias por este tutorial, ha sido de gran ayuda y era lo que andaba buscando... mil gracias