2. Una tarde con AngularJS
En este capítulo vamos a ver todos los fundamentos de AngularJS para ponernos a trabajar rápidamente con el Framework.
Una vez terminada la sesión, seremos capaces de crear aplicaciones sencillas con AngularJS, y tendremos conocimiento de unos fundamentos que iremos desarrollando y ampliando en sesiones posteriores.
Todo el código que hagamos de aquí en adelante lo pondremos en un fork del proyecto Como hay una parte del código de los ejercicios que evolucionará a lo largo de las sesiones, identificaremos cada entrega mediante el uso de tags. El nombre de dichos tags se indicará en cada apartado de ejercicios. |
Aunque aquí se exlican una serie de pasos para crear una aplicación desde cero, lo que codifiquemos en esta sesión deberemos hacerlo dentro de la carpeta unatardeconangular de nuestro fork. |
2.1. Creando la aplicación
Para nuestra aplicación, crearemos un nuevo proyecto IntelliJ

Crearemos un proyecto vacío, que será la base de todos nuestros módulos y será lo que subiremos a BitBucket

Llamaremos al proyecto angular-expertojava

A continuación, introduciremos un nuevo módulo de tipo Static Web. Lo llamaremos unatardeconangular


2.2. Directivas, data binding
Dado que AngularJS es un framework JavaScript se se va a ejecutar en una página web, vamos a necesitar un fichero html. En éste, tendremos que incluir el código fuente de AngularJS.
1
2
3
4
5
6
7
8
9
10
11 <!DOCTYPE html>
<html ng-app>
<head>
<title>Una tarde con AngularJS</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script src="https://code.angularjs.org/1.5.0/angular.min.js"></script>
</body>
</html>
En el momento de escribir estos apuntes, la última versión estable es la 1.5.0. Cualquier versión posterior es totalmente compatible con lo que aquí veamos. |
Una vez añadido el script de AngularJS en nuestra página, ya podemos empezar a usarlo. Para esto, nos vamos a topar con el primero de los elementos propios de AngularJS: las directivas. Una directiva, como se ha mencionado, nos permite extender HTML, creando componentes, clases o atributos con una funcionalidad dada.
Por ejemplo, en el código de arriba, ya vemos nuestra primera directiva, y una de las más importantes: ng-app
. Por convenio, todo lo que tenga la forma ng-*
va a ser una directiva built in de AngularJS. Dado que no son exclusivas del core del framework y nosotros podemos crearnos nuestras propias directivas, por convenio las third parties suelen utilizar un prefijo de 2-3 caracteres para cada directiva y así evitar conflictos de nombres.
Volviendo a la directiva ng-app
. Ésta se encarga de inicializar nuestra aplicación. Lo más normal es ubicarla cerca del elemento raíz de la página, es decir, en las etiquetas <body>
o <html>
.
También podemos definir un módulo de AngularJS, que será nuestro módulo raíz para la aplicación. De momento, no le definiremos ningún nombre a la directiva ya que podemos hacer muchas cosas sin añadir ningún módulo. Por ejemplo, probemos el siguiente bloque de código:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 <!DOCTYPE html>
<html ng-app>
<head>
<title>Una tarde con AngularJS</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="components/lib/twitter-bootstrap/css/bootstrap.css" />
</head>
<body>
<div class="container">
<label>Nombre:</label> <input type="text" ng-model="name" /><br/>
Has escrito {{ name }}.
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
</body>
</html>
Aquí vemos en acción otra directiva fundamental de AngularJS, llamada ng-model
. Lo que hace esta directiva es crear una variable (en este caso llamada name porque estamos solicitando un nombre al usuario, pero podría ser surname o phone), en un elemento en memoria llamado scope
. Este scope
es un ViewModel que estaba vacío hasta que le hemos asignado esa propiedad. Para escribir ese valor del scope
en cualquier sitio de la vista, lo único que tenemos que hacer es usar la expresión de data binding {{ }}
.
Como algunos sabréis, la especificación de HTML5 dice que los custom attributes deben empezar con el prefijo data-
. Si en algún proyecto os encontráis que hay que seguir esta especificación no os preocupéis: el core de AngularJS soporta este prefijo e identifica todas las directivas que lo lleven.
Si probamos el código en nuestro navegador, veremos cómo el nombre se va escribiendo a medida que introducimos caracteres en el input, gracias a la acción del two way data binding.
2.3. Declarando colecciones e iterando sobre ellas
Otra cosa que podemos hacer es recorrer una colección. Para ello, AngularJS nos proporciona una directiva, ng-repeat
, que nos permite iterar sobre un array de elementos. Este array lo vamos a inicializar con otra directiva, llamada ng-init
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 <!DOCTYPE html>
<html ng-app>
<head>
<title>Una tarde con AngularJS</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="components/lib/twitter-bootstrap/css/bootstrap.css" />
</head>
<body>
<div class="container" ng-init="people = ['Domingo', 'Otto', 'Aitor', 'Eli', 'Fran', 'José Luís', 'Alex']">
<ul>
<li ng-repeat="person in people">{{ person }}</li>
</ul>
</div>
<script src="https://code.angularjs.org/1.5.0/angular.min.js"></script>
</body>
</html>
El uso de la directiva ng-init es muy similar a la declaración de variables dentro de código JavaScript. Por suerte, muy pronto veremos que no vamos a inicializar variables de esta manera, ya que como imaginaréis una vista no es el mejor lugar para inicializar una variable.
Por su parte, hemos visto que únicamente hemos declarado una plantilla para la colección, y ha sido la directiva ng-repeat
quien se ha encargado de instanciarla para cada elemento de la colección. El formato de expresión más utilizado para esta directiva es variable in expression
, donde variable
es el nombre de una variable definida por el usuario, y expression
es el nombre de nuestra colección. Más adelante, veremos que hay más expresiones que podemos usar con esta directiva.
2.4. Filtros
Otra cosa que podemos usar en AngularJS son filtros. Un filtro se encarga de recibir entrada determinada, realizar una transformación sobre ella, y devolver el resultado de la misma.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 <!DOCTYPE html>
<html ng-app>
<head>
<title>Una tarde con AngularJS</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="components/lib/twitter-bootstrap/css/bootstrap.css" />
</head>
<body>
<div class="container" ng-init="people = [{name:'Domingo', subject:'JPA'}, {name:'Otto', subject:'Backbone'}, {name:'Aitor',subject:'JavaScript'}, {name:'Miguel Ángel',subject:'JHD'}, {name:'Eli', subject:'REST'}, {name:'Fran', subject:'Grails'}, {name:'José Luís', subject:'PaaS'}, {name:'Alex', subject:'AngularJS'}]">
<label>Filtro:</label> <input type="text" ng-model="textFilter" /><br/>
<ul>
<li ng-repeat="person in people | filter:textFilter | orderBy:'name'">{{ person.name }} - {{ person.subject | uppercase }}</li>
</ul>
</div>
<script src="https://code.angularjs.org/1.5.0/angular.min.js"></script>
</body>
</html>
AngularJS dispone de una gran cantidad de filtros predefinidos. En el bloque de código anterior, vemos cómo utilizamos, el filtro uppercase
para transformar una cadena a mayúsculas una cadena, o el filtro orderBy
nos permite ordenar una colección de elementos. También vemos que podemos encadenar tantos filtros como queramos. En la directiva ng-repeat
usamos los filtros filter
y orderBy
.
Al encadenar filtros, el resultado se irá propagando al siguiente en el orden que los hemos declarado. En este caso, primero Hemos usado el filtro filter
para filtrar elementos basándonos en el modelo textFilter
. Luego, hemos ordenado el conjunto de resultados por la propiedad name
.
Para no repetirnos en el uso de filtros ya tienen cierto coste computacional, podemos declarar variables en una directiva ng-repeat
:
1
2
3
4 <ul>
<li ng-repeat="person in filteredPeople = (people | filter:textFilter | orderBy:'name')">{{ person.name }} - {{ person.subject | uppercase }}</li>
</ul>
Encontrados {{ filteredPeople.length }} resultados.
Nos detendremos en el capítulo dedicado a filtros a explicar cómo funciona cada uno de ellos. También, veremos cómo construir nuestros propios filtros.
2.5. Vistas, módulos, controladores y scope
Vamos a centrarnos ahora en la parte MVVM de AngularJS. Las Vistas y Controladores serán similares a lo que hemos visto en otros frameworks, y además disponemos de un elemento, llamado scope
, que hace las veces de ViewModel.
En AngularJS, tenemos una vista, como las que hemos estado viendo en los anteriores ejemplos con sus filtros, sus directivas y su data binding. Como se ha comentado, no queremos declarar variables en la vista, porque hace nuestro código menos portable y testable. Para estos menesteres, disponemos de un objeto JavaScript llamado Controller
, que va a gestionar qué datos se pasan a la vista, si éstos se actualizan y, también, va a comunicarse con el servidor en caso de que haya que actializar información en su lado.
Entre la vista y el controlador, hay un elemento llamado scope
. El scope
es el "pegamento" que une la vista y el controlador. Ni la vista sabe nada del controlador, ni el controlador de la vista. Nuevamente, esto nos permite hacer nuestro código muy modular y testable, al no haber una relación directa entre estos elementos.
Otra ventaja, es que podemos tener un único controlador vinculado a diferentes vistas. Por ejemplo, podemos tener una vista para una versión mobile otra para una versión desktop asociadas al mismo controlador.
¿Y qué es exactamente un ViewModel? Un ViewModel no es, ni más ni menos, que los datos que van a ser gestionados por la vista. Y eso es lo que el scope
es.
Vamos a transformar nuestro último ejemplo, creando un controlador y pasando los datos a la vista, en lugar de declararlos en ella.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 <!DOCTYPE html>
<html ng-app="teachersApp">
<head>
<title>Una tarde con AngularJS</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="components/lib/twitter-bootstrap/css/bootstrap.css"/>
</head>
<body>
<div class="container" ng-controller="TeachersCtrl">
<label>Filtro:</label> <input type="text" ng-model="textFilter"/><br/>
<ul>
<li ng-repeat="person in filteredPeople = (people | filter:textFilter | orderBy:'name')">{{ person.name }} - {{
person.subject | uppercase }}
</li>
</ul>
Encontrados {{ filteredPeople.length }} resultados.
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script>
var teachersApp = angular.module('teachersApp', []);
teachersApp.controller('TeachersCtrl', function TeachersCtrl($scope) {
$scope.people = [
{name: 'Domingo', subject: 'JPA'},
{name: 'Otto', subject: 'Backbone'},
{name: 'Aitor', subject: 'JavaScript'},
{name: 'Miguel Ángel', subject: 'JHD'},
{name: 'Eli', subject: 'REST'},
{name: 'Fran', subject: 'Grails'},
{name: 'José Luís', subject: 'PaaS'},
{name: 'Alex', subject: 'AngularJS'}
];
});
</script>
</body>
</html>
Vemos que hemos tenido que realizar lo que se conoce como un módulo. Dentro de nuestro objeto module es donde vamos a poder configurar nuestras rutas, y también definir filtros, directivas, controladores, factorías, y demás servicios que serán específicos para nuestra app. Podríamos pensar en un module como un contenedor de objetos donde podemos tener todas estas cosas.
Ésos corchetes vacíos los utilizaremos para establecer dependencias de nuestro módulo con otros. De momento, nuestro módulo no va a tener ningún tipo de dependencias con nadie.
En el ejemplo, hemos decidido refactorizar nuestro código y crear una función anónima para el controlador. Recordemos que esto es JavaScript, donde las funciones se pueden pasar como argumentos. Otra manera de hacer lo mismo tocando menos código hubiera sido:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 function TeachersCtrl($scope){
$scope.people = [
{name:'Domingo', subject:'JPA'},
{name:'Otto', subject:'Backbone'},
{name:'Aitor',subject:'JavaScript'},
{name:'Miguel Ángel',subject:'JHD'},
{name:'Eli', subject:'REST'},
{name:'Fran', subject:'Grails'},
{name:'José Luís', subject:'PaaS'},
{name:'Alex', subject:'AngularJS'}
];
}
var teachersApp = angular.module('teachersApp', []);
teachersApp.controller('TeachersCtrl', TeachersCtrl);

Además, hemos creado un controlador. Podemos ver que nuestro controlador es, básicamente, una función JavaScript. Una cosa interesante es que le pasamos como parámetro la variable $scope. Este $scope se pasa por Inyección de Dependencias, otra de las características de AngularJS de las que hemos hablado. En el momento en que se usa este controlador, AngularJS le inyectará de manera automática el objeto $scope. Una vez lo tenga, el controlador le añade una propiedad, llamada people, que es el array que anteriormente habíamos declarado en nuestra vista.
El controlador actúa como fuente de datos para la vista, pero no debería saber nada de la vista. Así que por eso inyectamos la variable $scope. Ésta va a permitir que nuestro controlador se comunique con la vista. El $scope pasará a la vista, una vez ésta sepa cuál es el controlador que la gestiona. Esto lo conseguimos gracias al atributo ng-controller="TeachersCtrl". El scope estará visible para el div que lo ha llamado, así como para sus hijos. Vemos que el resto de nuestro código no ha variado y podemos seguir accediendo a la colección people. Solo que ahora estamos accediendo a la propiedad people del $scope.
El encargado de obtener el controlador es la ng-app, ya que lo hemos declarado en el módulo teachersApp.
2.6. Rutas y Factorías
En AngularJS, todo módulo debe tener una función de configuración. En esta función es donde, entre otras cosas, podemos definir rutas. Las rutas son importantes porque si nuestra aplicación tiene varias vistas, y éstas deben ser cargadas en nuestra página, debemos entonces tener un mecanismo para saber dónde estamos, qué vista tenemos asociada, qué controlador la gestiona…
Cuando definimos una ruta en AngularJS, también debemos definir dos elementos:
-
Una vista. Por ejemplo, si estamos en la ruta
/profile
, entonces mostraremos la vista/partials/profile.html
-
Un controlador. En lugar de definir el controlador en la vista con la etiqueta
ng-controller
, podemos establecerlo al definir una ruta. Siguiendo con el ejemplo anterior, asociaríamos el controladorProfileCtrl
Un controlador no debería tener toda la lógica de la aplicación. En una aplicación bien estructurada, esta lógica la sacaríamos fuera a unos objetos que, en AngularJS, se llaman Factories, Services y Providers.
En la vista, tenemos el apoyo de las directivas y filtros, algunos de las cuales ya hemos visto.

Una vez hemos definido un módulo y un controlador, en algún momento vamos a tener que definir rutas para nuestra aplicación SPA.
Veamos aquí un ejemplo de rutas para una aplicación. En algún momento, debido a un evento, nuestra aplicación pasará de la vista 1 a la 2, mapeada por la ruta /view2
, de la 2 a la 3… y así realizando un ciclo.

Lo importante aquí es saber que, con el cambio de ruta, no se recargará la página completa, sino el bloque que nosotros hayamos indicado.
La manera de definir estos bloques puede ser:
-
Como una plantilla dentro de nuestro
index.html
. -
Como ficheros HTML independientes, habitualmente conocidos como
partials
. Ésta suele ser la manera habitual de hacerlo, sobre todo en aplicaciones grandes.
A partir de la versión 1.2, el módulo de rutas se extrajo del core de AngularJS como módulo independiente, con lo que lo primero que tendremos que hacer es traernos este módulo:
1 <script src="https://code.angularjs.org/1.5.0/angular-route.min.js"></script>
Como hemos mencionado anteriormente, para incluir módulos extras en el nuestro, tenemos que declararlo en la definición:
1 var teachersApp = angular.module('teachersApp', ['ngRoute']);
Una vez hecho esto, ya podemos definir las rutas. Hemos dicho anteriormente que un módulo de AngularJS tenía una función de configuración, donde definíamos las rutas. Vamos a usar esta función, a la que tenemos que inyectarle un objeto llamado $routeProvider.
Vamos a definir dos rutas en nuestra aplicación:
-
La primera será el listado de profesores que hemos hecho antes.
-
La segunda consistirá en una página de asignaturas. Como aún no lo hemos implementado, mostrará un bonito mensaje de En construcción.
En cualquier otro caso, podemos definir una ruta por defecto a la que seremos redirigidos si introducimos algo a donde nuestra aplicación no sabe qué hacer con ello. Para este ejemplo, será la lista de profesores:
1
2
3
4
5
6
7
8
9
10
11 teachersApp.config(function($routeProvider){
$routeProvider
.when('/teachers',{
controller : 'TeachersCtrl',
templateUrl : 'teachers.html'
})
.when('/subjects',{
templateUrl : 'subjects.html'
})
.otherwise({ redirectTo : '/teachers'});
});
Para cada ruta, podemos definir una plantilla y un controlador. La configuración de rutas no obliga a introducir un par controlador - plantilla, como vemos en la segunda ruta.
Para adaptar nuestra aplicación a lo que acabamos de definir, tenremos que crearnos una página HTML, a la que llamaremos teachers.html. En ella estará el listado de profesores.
1
2
3
4
5 <label>Filtro:</label> <input type="text" ng-model="textFilter" /><br/>
<ul>
<li ng-repeat="person in filteredPeople = (people | filter:textFilter | orderBy:'name')">{{ person.name }} - {{ person.subject | uppercase }}</li>
</ul>
Encontrados {{ filteredPeople.length }} resultados.
Tendremos que refactorizar nuestro fichero index.html
e introducir una nueva directiva, llamada ng-view
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 <!DOCTYPE html>
<html ng-app="teachersApp">
<head>
...
</head>
<body ng-controller="teachersCtrl">
<div class="container">
<ul class="nav nav-pills nav-justified">
<li><a href="#/teachers">Profesores</a></li>
<li><a href="#/subjects">Asignaturas</a></li>
</ul>
<ng-view></ng-view>
</div>
<script src="https://code.angularjs.org/1.5.0/angular.min.js"></script>
<script src="https://code.angularjs.org/1.5.0/angular-route.min.js"></script>
<script>
...
</script>
</body>
</html>
La directiva ng-view complementa al servicio $route, incluyendo la plantilla que hemos definido en la función config. Cada vez que la ruta cambia, la vista cambiará en función de lo configurado. La directiva ng-view puede ser tanto una etiqueta como un atributo, con lo que os la podréis encontrar habitualmente con la forma: <div ng-view></div>.
Justo antes de la directiva ng-view hemos definido dos links, que nos permitirán navegar por la aplicación. Al no estar incluídos dentro del bloque ng-view, éstos permanecerán invariables durante toda la navegación.
Haciendo click en el enlace asignaturas, llegaremos a una página en construcción, que mantiene los elementos. Observando la barra de dirección, veremos que la ruta ha cambiado. Y lo más increíble de todo, es que si hacemos click en el back button del navegador, volveremos al listado de profesores. El histórico del navegador funciona… ¡y sin hacer nada! AngularJS se encarga de gestionar el histórico del navegador.
2.6.1. Comunicándonos con el controlador
Ahora que tenemos nuestra lógica de navegación implementada, vamos a ver de qué manera podemos comunicarnos con el controlador. Para ello, en el listado de profesores, vamos a introducir la posibilidad de crear uno nuevo.
1
2
3
4
5
6
7
8
9
10
11 <h1>Profesorado</h1>
<label>Filtro:</label> <input type="text" ng-model="textFilter" /><br/>
<ul>
<li ng-repeat="person in filteredPeople = (people | filter:textFilter | orderBy:'name')">{{ person.name }} - {{ person.subject | uppercase }}</li>
</ul>
Encontrados {{ filteredPeople.length }} resultados.
<br/><br/>
<h2>Nuevo profesor</h2>
<label>Nombre:</label> <input type="text" ng-model="newTeacher.name" /><br/>
<label>Asignatura</label> <input type="text" ng-model="newTeacher.subject" /><br/>
<button ng-click="addTeacher()">Guardar</button>
Fijémonos en el botón, que incorpora una nueva directiva, llamada ng-click
. Ésta responde al evento onClick
, realizando una llamada a la función addTeacher()
.
Como hemos dicho antes, la vista no sabe nada del controlador. Pero disponemos del objeto $scope
, que permite exponer elementos del controlador en la vista. Lo hemos hecho con una colección (el array de profesores), y también podemos exponer una función:
1
2
3
4
5
6
7
8
9
10
11
12 teachersApp.controller('teachersCtrl', function($scope){
$scope.people = [
...
];
$scope.addTeacher = function() {
$scope.people.push({
name : $scope.newTeacher.name,
subject : $scope.newTeacher.subject
});
};
});
Vemos que no se ha pasado ningún dato como parámetro, ya que al pasarlo como ng-model
en nuestros inputs, ya lo podemos obtener a través del $scope
.
2.7. Usando factorías y servicios
Una de las cosas que observamos en nuestra aplicación, es que si pasamos del listado de profesores al de asignaturas y luego volvemos a los profesores otra vez, es que los que hayamos podido introducir han desaparecido. Esto es porque los datos están vinculados al objeto $scope, que se crea y se destruye con cada cambio de ruta.
AngularJS nos permite encapsular los datos de nuestra aplicación en una serie de elementos:
-
Factorías
-
Servicios
-
Providers
-
Valores
-
Constantes
Los tres primeros (Factorías, Servicios y Providers), además de datos, nos permiten encapsular funcionalidades dentro de nuestra aplicación. Por ejemplo, si necesito mi lista de profesores en múltiples controladores, lo correcto sería guardarlos en uno de estos elementos.
Estos tres elementos pueden realizar la misma funcionalidad, y la diferencia entre ellos radica en cómo se crean. Lo veremos más adelante.
Además, estos elementos implementan el patrón singleton, lo que los convierte en los candidatos perfectos para intercambiar información entre controladores.
Así, ahora vamos a modificar nuestro código para utilizar una factoría, donde podremos obtener el listado de profesores, así como añadir ítems a la lista. Una factoría en AngularJS devuelve un objeto javascript, con lo que su forma será la siguiente:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 teachersApp.factory('teachersFactory', function(){
var teachers = [
{name:'Domingo', subject:'JPA'},
{name:'Otto', subject:'Backbone'},
{name:'Aitor',subject:'JavaScript'},
{name:'Miguel Ángel',subject:'JHD'},
{name:'Eli', subject:'REST'},
{name:'Fran', subject:'Grails'},
{name:'José Luís', subject:'PaaS'},
{name:'Alex', subject:'AngularJS'}
];
return {
getTeachers : function() {
return teachers;
},
addTeacher : function(newTeacher) {
teachers.push({
name : newTeacher.name,
subject : newTeacher.subject
})
}
}
});
Más adelante en el curso, veremos de qué manera podemos obtener ese listado de profesores a través de una llamada AJAX o un servicio REST, en lugar de tener ese array harcodeado en nuestra factoría.
Al crear la factoría, podemos usarla en nuestro controlador simplemente inyectándola como parámetro. Así, ya estará disponible y podremos usarla:
1
2
3
4
5
6
7 teachersApp.controller('teachersCtrl', function($scope, teachersFactory){
$scope.people = teachersFactory.getTeachers();
$scope.addTeacher = function() {
teachersFactory.addTeacher($scope.newTeacher);
};
});
La inyección de dependencias no se limita sólo a controladores, como veremos más adelante, podemos inyectar una factoría en otra factoría, o cualquiera de los elementos propios de AngularJS.
Como hemos dicho, una factoría implementa el patrón singleton. Esto significa que se instancia una única vez (la primera vez que es requerida), y está disponible durante toda la vida de la aplicación. Ahora, si nos vamos al listado de asignaturas y volvemos al de profesores, veremos que no perdemos los datos que hayamos podido introducir.
Otra cosa que debemos saber, es que AngularJS permite encadenar operaciones. Esto significa que podemos refactorizar nuestro código de la siguiente manera:
1
2
3
4
5
6
7
8
9
10
11 angular
.module('teachersApp', ['ngRoute'])
.config(function($routeProvider){
...
})
.controller('teachersCtrl', function($scope, teachersFactory){
...
})
.factory('teachersFactory', function(){
...
});
2.8. Ejercicio (1 punto)
Sube el código que hayas hecho en esta sesión, y aplícale el tag intro
a la versión que quieres que se corrija.
Todo el código de la sesión estará dentro de una carpeta llamada intro
también.
Tras haber realizado este breve tutorial, ya tenemos unos fundamentos bastante básicos del core
de AngularJS. Opcionalmente, podemos ampliar nuestra aplicación realizando los siguientes incrementos:
-
En el formulario de alta de profesores, introduciremos un nuevo campo que nos permita añadir la descripción de la asignatura.
-
En el listado de asignaturas, mostraremos un listado de las asignaturas disponibles en el curso, y su descripción. Para ello crearemos el controlador subjectsCtrl
-
Introduciremos la opción de eliminar un profesor. Quizá pueda ser interesante el uso de la función splice de JavaScript, así como echarle un ojo a la documentación de la directiva
ngRepeat
de AngularJS, a ver si podemos encontrar la manera de hacer uso de los índices.