En el capitulo anterior hemos visto como configurar el index.html y require (main-dev) para que funcione con angular. Ahora vamos a adaptar nuestro código (o a implementarlo desde cero) para que dicha configuración tenga sentido.
Empezaremos comentando como queda el fichero de controllers. Con este ejemplo se puede pasar cualquier modulo angular a modulo / modulos de requirejs. Allá vamos:
[code language=”javascript”]
define([“angular”, “js/services”], function(angular){
/* Controllers Module */
var controllers = angular.module(‘controllers’, [“services”]);
controllers.controller(‘MoviesListPresenter’, [‘$scope’, ‘Movie’,
function($scope, Movie) {
$scope.movies = Movie.query();
}]);
return controllers;
})
[/code]
Aquí definimos un módulo de require con angular y services como dependencias. Inyectamos la variable “angular” en la función, definimos un módulo de angular de controllers y creamos un nuevo controlador llamado “MovieListPresenter“. El hecho de llamarlo “presenter” viene porque en el seed project viene implementado otro patrón de diseño, en concreto el MVP, en vez del todo conocido MVC. De cara a la configuración o migración es indiferente.
Como vemos, la manera de crear el controlador es prácticamente la misma. Lo único que cambia, es que ahora viene dentro del módulo de require. También, prestar atención a que, por ejemplo, con los services, tenemos dos tipos de dependencia. La primera es la de require y la segunda es la de angular.
Ahora, en el ejemplo de los “services”, veremos como definir un módulo mas común: el que viene con factories.
[code language=”javascript”]
define([“angular”, “angular-resource”], function(angular){
/* Services Module */
var services = angular.module(‘services’, [‘ngResource’]);
services.factory(‘Movie’, [‘$resource’,
function($resource){
return $resource(‘movies/movies.json’, {}, {
query: {method:’GET’, params:{}, isArray:true}
});
}
]);
return services;
})
[/code]
Es prácticamente lo mismo, lo único que cambia en la definición es que en vez de .controller, tenemos .factory
Llegados a este punto, el panorama pinta bien, pero en una aplicación rara vez vaya a haber un solo controlador o un solo servicio. Y en cuanto el numero de ellos crezca, tenerlo todo metido en un solo fichero sería un desastre. Aquí viene lo bueno. Mirad en el ejemplo como partimos services para tener una definición del módulo y luego la de cada servicio en un fichero diferente:
[code language=”javascript”]
define([“angular”, “angular-resource”], function(angular){
/* Services Module */
var services = angular.module(‘services’, [‘ngResource’]);
return services;
})
[/code]
Aqui definimos el módulo tanto a nivel de require como de angular, retornando la variable services. Y luego:
[code language=”javascript”]
define([“angular”, “js/services”], function(angular, services){
services.factory(‘Movie’, [‘$resource’,
function($resource){
return $resource(‘movies/movies.json’, {}, {
query: {method:’GET’, params:{}, isArray:true}
});
}
]);
})
[/code]
Requerimos el módulo require y le añadimos a la variable services una factory con el servicio que queremos. Así el módulo de services puede ir creciendo de manera limpia y ordenada.
Con los controllers hacemos lo mismo:
[code language=”javascript”]
//controllers.js
define([“angular”, “js/services”], function(angular){
/* Controllers Module */
var controllers = angular.module(‘controllers’, [“services”]);
return controllers;
})
[/code]
[code language=”javascript”]
//MovieListPresenter.js
define([“angular”,”js/controllers”, “services/MovieService”], function(angular, controllers){
controllers.controller(‘MoviesListPresenter’, [‘$scope’, ‘Movie’,
function($scope, Movie) {
$scope.movies = Movie.query();
}
]);
})
[/code]
Con esto podemos definir cualquier módulo. Falta ver como lo llamamos desde app.js
[code language=”javascript”]
define([“angular”, “angular-resource”, “angular-route”,”js/controllers”, “js/filters”,
“controllers/MoviesListPresenter”
], function(angular){
/* App Module */
var moviesApp = angular.module(‘moviesApp’, [
‘ngResource’,
‘ngRoute’,
‘controllers’,
‘filters’
]);
moviesApp.config([‘$routeProvider’,
function($routeProvider) {
$routeProvider.
when(‘/movies’, {
templateUrl: ‘partials/movies-list.html’,
controller: ‘MoviesListPresenter’
}).
otherwise({
redirectTo: ‘/movies’
});
}]);
angular.bootstrap(document, [‘moviesApp’]);
return moviesApp;
})
[/code]
Aquí, tendremos que requerir, además de los módulos de librerías externas, los módulos de definición de controladores y servicios. También, como los controladores los utilizamos en el propio fichero app.js, habrá que requerirlos uno por uno. Los ficheros concretos de servicios no se ponen aquí, sino en los controladores, o donde se necesiten.
Un último apunte a tener muy en cuenta: en el capítulo anterior, cuando vimos como quedaba index.html, si os habíais fijado, la directiva ng-app no estaba. Y es porque con requirejs tenemos que lanzar la aplicacion expresamente:
[code language=”javascript”]
angular.bootstrap(document, [‘moviesApp’]);
[/code]
Esto pasa por la carga asíncrona de archivos. Cuando se ejecuta el index, los js aun no están disponibles 🙁
Bueno, por fin tenemos una aplicación funcional! Ha sido bastante rollo, pero ya veréis como os será mucho fácil trabajar de esta forma. Y cuando veáis los tests, os gustará más aun…
Pero dejémoslo para la próxima entrega!