====== 3.7 service ====== Hemos visto por ahora 2 tipos de servicio , las ''constant'' y los ''value''. En ambos casos le pasábamos directamente el valor que debía tener el servicio. Con el tipo ''service'' (( que en este tema no referimos al tipo concreto ''service'' y no a los servicios en general )) le debemos pasar una //clase// ((Es una función que actúa como constructor)) JavaScript y será AngularJS el que cree internamente una instancia de la clase. Lo veremos mas claro con el siguiente ejemplo: var app=angular.module("app",[]); function Rectangulo() { this.ancho=0; this.alto=0; this.setAncho=function(ancho) { this.ancho=ancho; } this.setAlto=function(alto) { this.alto=alto; } this.getArea=function() { return this.ancho * this.alto; } } app.service("rectangulo",Rectangulo); app.controller("PruebaController",["$scope","rectangulo",function($scope,rectangulo) { rectangulo.setAncho(3); rectangulo.setAlto(6); $scope.area=rectangulo.getArea(); }]); * Línea 3: Aquí hemos definido la función JavaScript con el constructor de nuestra clase llamada "Rectangulo". * Línea 20: Llamamos al método ''service'' y le pasamos como segundo parámetro la función con el constructor de la clase "Rectangulo". ===== Inyectando el constructor ===== Una funcionalidad que permite AngularJS es que le podamos inyectar servicios en el propio constructor. En el ejemplo anterior veíamos que el ancho y alto inicial era 0 , pero es un problema que los valores iniciales están //grabados a fuego// en el interior de la clase. Es mucho mas interesante que se puedan incluir en el constructor para que podamos elegir los que queramos. Así que la clase quedará de la siguiente forma: function Rectangulo(tamanyoInicial) { this.ancho=tamanyoInicial.ancho; this.alto=tamanyoInicial.alto; this.setAncho=function(ancho) { this.ancho=ancho; } this.setAlto=function(alto) { this.alto=alto; } this.getArea=function() { return this.ancho * this.alto; } } * Línea 1: Ahora el constructor acepta como parámetro un objeto con las propiedades ''ancho'' y ''alto''. * Línea 2: Se asigna como ancho inicial el valor de la propiedad ''tamanyoInicial.ancho'' * Línea 3: Se asigna como alto inicial el valor de la propiedad ''tamanyoInicial.alto'' Lo siguiente es hacer que haya un servicio ''value'' que contenga el tamaño inicial del rectángulo. app.value("tamanyoInicialRectangulo",{ ancho:2, alto:3 }); Y ahora nos queda inyectar el ''value'' "tamanyoInicialRectangulo" en el constructor de "Rectangulo" y AngularJS por suerte ya tiene esa funcionalidad programada ((A mí me recuerda a Spring que también permite inyectar dependencias en los constructores)). app.service("cuadrado",['tamanyoInicialRectangulo',Cuadrado]); Vemos que junto al nombre del constructor que es ''Cuadrado'' hemos incluido el típico array de AngularJS con el nombre de los servicios a inyectar, que en nuestro caso es el ''value'' llamado ''tamanyoInicialRectangulo'' El ejemplo completo quedaría de la siguiente forma: var app=angular.module("app",[]); app.value("tamanyoInicialRectangulo",{ ancho:2, alto:3 }); function Rectangulo(tamanyoInicial) { this.ancho=tamanyoInicial.ancho; this.alto=tamanyoInicial.alto; this.setAncho=function(ancho) { this.ancho=ancho; } this.setAlto=function(alto) { this.alto=alto; } this.getArea=function() { return this.ancho * this.alto; } } app.service("rectangulo",['tamanyoInicialRectangulo',Rectangulo]); app.controller("PruebaController",["$scope","rectangulo",function($scope,rectangulo) { $scope.area=rectangulo.getArea(); }]); Hay que hacer notar que el nombre del ''value'' que se inyecta se llama "tamanyoInicialRectangulo" mientras que el parámetro del constructor se llama "tamanyoInicial". Es decir que tienen nombres distintos. No hay problema en ello ya que una vez inyectado el valor da igual el nombre del parámetro del constructor. Si no hubiéramos usado el array sí que se deberían de haber llamado igual , por lo que éste es un motivo más para usar siempre el array. ===== Service vs value ===== Ahora, ¿qué hemos ganado usando un ''service'' en vez de un ''value'' cuando el valor es una objeto de una clase? Si no necesitamos inyección de dependencias en el constructor la verdad es que no hemos ganado mucho. El ejemplo inicial se podría haber hecho como un ''value'' de la siguiente forma: var app=angular.module("app",[]); function Rectangulo() { this.setAncho=function(ancho) { this.ancho=ancho; } this.setAlto=function(alto) { this.alto=alto; } this.getArea=function() { return this.ancho * this.alto; } } app.value("rectangulo",new Rectangulo()); app.controller("PruebaController",["$scope","rectangulo",function($scope,rectangulo) { rectangulo.setAncho(3); rectangulo.setAlto(6); $scope.area=rectangulo.getArea(); }]); * Línea 18: Le pasamos directamente el objeto de la clase en vez de que internamente sea AngularJS el que cree el objeto. Realmente no hay mucha diferencia ya que como veremos mas adelante, tanto los [[unidades:03_servicios:06_value|value]] como los [[unidades:03_servicios:07_service|service]] como los [[unidades:03_servicios:08_factory|factory]] son solamente //azucar sintáctico// respecto a los [[unidades:03_servicios:09_provider|provider]]. Es decir , internamente para AngularJS son únicamente un [[unidades:03_servicios:09_provider|provider]] pero al ser los [[unidades:03_servicios:09_provider|provider]] un poco complejos de programar se han creado estas funciones para simplificar su uso. Pero aun así, yo veo una ventaja de un ''service'' sobre un ''value'' cuando es un objeto de una clase. Si un servicio nunca se va a usar , AngularJS no lo inicializará por lo tanto usando un ''service'', nos podríamos ahorrar el gasto de crear la instancia si no llegara a usarse o al menos retrasarlo hasta que se use, mientras que con un ''value'' siempre se crearía. Esto que puede parecer poca cosa, podría implicar gran gasto de recursos en grandes aplicaciones en las que hay gran cantidad de servicios y también debemos añadir todos los servicios que crean las librerías de terceros que usemos. Es preferible usar un ''service'' en vez de un ''value'' cuando es una instancia de una clase ya que: * Nos podemos ahorrar la creación de la instancia o al menos retrasarla hasta que sea necesaria * Permite inyectar dependencias en el constructor ===== Ejemplo ===== {{url>http://embed.plnkr.co/9RJnmH}} ===== Referencias ===== * [[https://docs.angularjs.org/guide/providers#service-recipe|/ Developer Guide / Providers / Service]]