> Manuales > Manual de AngularJS

Explicaciones sobre ngRoute, el módulo de AngularJS que nos permite crear rutas profundas en nuestra aplicación e intercambiar vistas dependiendo de la ruta.

Hasta ahora en el Manual de AngularJS hemos visto muchas cosas interesantes, sin embargo nos hemos limitado a hacer aplicaciones en las que solo teníamos una ruta y una vista. Sin embargo, cuando se vayan complicando los requisitos de nuestras aplicaciones podremos necesitar ampliar estas posibilidades.

Lo que vamos a aprender ahora es a crear rutas distintas dentro de nuestra aplicación, de modo que tengamos varias URL que muestran vistas distintas. Quizás te preguntes ¿Si AngularJS está especialmente indicado para hacer aplicaciones de una sola página (concepto que se conoce con el nombre de "Single Page Application", SPA), por qué ahora nos muestras la posibilidad de crear varias URL? ¿No era una única página lo que queríamos hacer?

Pues bien, podemos tener ambas cosas. Una aplicación de una sola página, pero que es capaz de representar URL distintas, simulando lo que sería una navegación a través de la aplicación, pero sin salirnos nunca de la página inicial. Esto nos sirve para varias cosas, entre otras:

Cómo son las rutas internas de la aplicación

Para que nos entendamos, en nuestra aplicación vamos a poder tener varias URL. Podrán tener una forma como esta:

http://example.com/index.php
http://example.com/index.php#/seccion
http://example.com/index.php#/pagina_interna

Son simples ejemplos, lo importante es fijarse en el patrón "#/". Podrás darte cuenta que estas URL corresponden con la misma página, todas, pues usan el carácter "#" que nos sirve para hacer lo que se llaman "enlaces internos" dentro del mismo documento HTML. Como sabemos, la "almohadilla" ("gato", "numeral", "sostenido" o como la llames en tu país), sirve para hacer rutas a anclas internas, zonas de una página.

Cuando le pidamos al navegador que acceda a una ruta creada con "#" éste no va a recargar la página, yéndose a otro documento. Lo que haría es buscar el ancla que corresponda y mover el scroll de la página a ese lugar.

Nota: Éste es el comportamiento de cualquier navegador, no estamos apuntando nada que tenga que ver con Javascript o con AngularJS. Angular, así como otros frameworks Javascript MVC se aprovechan de esta característica para implementar el sistema de enrutado.

En el caso de AngularJS no habrá un movimiento de scroll, pues con Javascript se detectará el cambio de ruta en la barra de direcciones para intercambiar la vista que se está mostrando.

Por ello, volviendo a la pregunta de antes: "si la posibilidad de crear varias rutas dentro de una aplicación contradice el sistema de Single Page Application", observamos que realmente no son páginas distintas, sino que es la misma página. Lo que estamos haciendo es "simular" la navegación por varias URL cuando realmente es la misma, con enlaces internos.

Instalar ngRoute

El módulo ("module" en la terminología anglosajona de Angular) ngRoute es un potente paquete de utilidades para configurar el enrutado y asociar cada ruta a una vista y un controlador, tal como hemos dicho. Sin embargo este módulo no está incluido en la distribución de base de Angular, sino que en caso de pretender usarlo tenemos que instalarlo y luego inyectarlo como dependencia en el módulo principal de nuestra aplicación.

Como no lo tenemos en el script básico de Angular, debemos instalarlo "a mano". lo conseguimos incluyendo el script del código Javascript del módulo ngRoute.

<script src="angular-route.js"></script>

Nota: Ojo que esta ruta no debes copiar y pegarla tal cual. Muchas veces usarás el CDN correspondiente y deberás asegurarte de estar usando en el módulo ngRoute de la misma versión de AngularJS que cargaste inicialmente. Otro detalle es que este script lo tienes que incluir después de haber incluido el script del core de AngularJS.

Inyección de dependencias

El segundo paso sería inyectar la dependencia con ngRoute en el módulo general de nuestra aplicación. Esto lo hacemos en la llamada al método module() con el que iniciamos cualquier programa AngularJS, indicando el nombre de las dependencias a inyectar en un array.

angular.module("app", ["ngRoute"])

Hasta ahora este array de dependencias, cuando llamábamos a angular.module(), estaba siempre vacío. A medida que se compliquen nuestras aplicaciones podremos necesitar inyectar más cosas. Por ejemplo, las directivas creadas por terceros desarrolladores también las inyectarás de esta manera en tu módulo principal de la aplicación. Eso lo veremos más adelante.

Configurar el sistema de enrutado con $routeProvider

El sistema de enrutado de AngularJS nos permite configurar las rutas que queremos crear en nuestra aplicación de una manera declarativa. Aunque sea un componente bastante complejo internamente, podemos configurarlo de una manera ciertamente sencilla.

$routeprovider tiene un par de métodos. El primero es when(), que nos sirve para indicar qué se debe hacer en cada ruta que se desee configurar, y el método otherwise() que nos sirve para marcar un comportamiento cuando se intente acceder a cualquier otra ruta no declarada.

Esta configuración se debe realizar dentro del método config(), que pertenece al modelo. De hecho, solo podemos inyectar $routeProvider en el método config() de configuración.

angular.module("app", ["ngRoute"])
    .config(function($routeProvider){
	//configuración y definición de las rutas
    });

Las rutas las configuras por medio del método when() que recibe dos parámetros. Por un lado la ruta que se está configurando y por otro lado un objeto que tendrá los valores asociados a esa ruta. De momento vamos a conocer solo éstos que serían los fundamentales para empezar.

Podemos ver un ejemplo completo de configuración de rutas.

angular.module("app", ["ngRoute"])
    .config(function($routeProvider){
        $routeProvider
            .when("/", {
                controller: "appCtrl",
                controllerAs: "vm",
                templateUrl: "home.html"
            })
            .when("/descargas", {
                controller: "appCtrl",
                controllerAs: "vm",
                templateUrl: "descargas.html"
            })
            .when("/opciones", {
                controller: "appCtrl",
                controllerAs: "vm",
                templateUrl: "opciones.html"
            });
    })
    .controller("appCtrl", function(){
        //código del controlador (lo estoy usando en todas las rutas, en este sencillo ejemplo)
    });

Hemos encadenado varias llamadas a métodos when() sobre el $routeProvider, para definir cada una de las rutas que tendremos en nuestra pequeña aplicación.

Nota: Observa que en cada una de las rutas tenemos definido el mismo controlador. Esto no tiene por qué ser así, podrías perfectamente tener un controlador distinto para cada ruta del sistema.

Para finalizar, podemos ver el código HTML de una página donde usaríamos estas rutas.

<body ng-app="app">
    <nav>
        <ul>
            <li><a href="#/">Datos personales</a></li>
            <li><a href="#/descargas">Descargas</a></li>
            <li><a href="#/opciones">Opciones de cuenta</a></li>
        </ul>
    </nav>
    <hr />

    <div ng-view></div>
    
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.24/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.24/angular-route.js"></script>
    <script src="app.js"></script>
</body>

Echa un vistazo a los enlaces que hay dentro de la etiqueta NAV. Esos son los enlaces que provocarían la navegación en el enrutado definido en la anterior configuración. Observarás que los href de los enlaces están asociados a las mismas rutas definidas en el $routeProvider. Por tanto, pulsando cada enlace Angular nos mostrará la vista indicada en la declaración que hemos mostrando antes en el config() del $routeProvider.

Tienes también que fijarte en la división DIV que hay más abajo que tiene la directiva ngView. En principio no necesitas indicar más cosas como valor de esa directiva. AngularJS ya sabe que las vistas las debe desplegar en ese contenedor.

Solo a modo de curiosidad, fíjate que en el HTML no hemos definido ningún controlador, osea, no está la directiva ng-controller por ninguna parte. Sin embargo, en las vistas internas sí que se está asociando un controlador, porque se ha declarado en el $routeProvider.

Nota: No queremos adelantarnos, pero si se te ocurre jugar con este prototipo y creas un poco de funcionalidad en el controlador que estamos usando en las vistas comprobarás que los datos se inicializan cada vez que accedemos a las vistas de nuevo. Esto lo explicaremos más adelante, así que no te preocupes si no has entendido todavía a qué nos estamos refiriendo.

Vistas independientes

Para acabar solo queda comentar el código de las vistas independientes. Tal como se definió en el $routeProvider, existe un código para cada una de las vistas, alojado en archivos HTML independientes. La vista alojada en "/" se llama "home.html", la vista de la ruta "/descargas" está en el archivo "descargas.html", etc. Esos archivos están en el mismo directorio que la vista principal, pero realmente podrían estar en cualquier otra ruta que especifiquemos.

El código que coloques en las vistas es indiferente. Simplemente pondrás HTML, directivas y todo lo que venimos usando hasta el momento en las vistas. Escribe el HTML que gustes, de momento no tiene más importancia.

Alberto Basalo

Alberto Basalo es experto en Angular y otras tecnologías basadas en Javascript,...

Manual