Tabla de Contenidos

3.10 Ejemplo servicio

En este tema retornamos el ejemplo del seguro médico para añadir un provider.

Al ver el servicio $http en el tema 3.2 $http vimos que no debía hacerse una llamada a $http en el propio controlador . Ahora vamos a crear un provider que encapsule la llamada a $http.

El servicio será un objeto llamado remoteResource que nos permitirá acceder al servidor para acceder a los datos. Como aún no hemos visto la parte de servidor ni la parte de REST ni las promesas , sólo vamos a hacer un único método sencillo que nos permita leer los datos. Más adelante en el curso seguiremos mejorando este servicio. Por lo tanto aun será un poco chapuza el ejemplo.

La configuración

Nuestro servicio va a ser un provider ya que tenemos que indicar la url a partir de la que debemos bajar los datos. Como hemos hecho en el tema anterior éso lo pondremos en una constante de nuestra aplicación.

app.constant("baseUrl",".");

La constante vale el valor ”.” porque los datos a bajar están en la misma ruta que nuestra página web.

El provider tendrá un único método para configurarlo llamado setBaseUrl por lo que tendremos el siguiente bloque config:

app.config(['baseUrl','remoteResourceProvider',function(baseUrl,remoteResourceProvider){
  remoteResourceProvider.setBaseUrl(baseUrl);
}]);

Fíjate cómo el nombre del provider es “remoteResourceProvider”, es decir que acaba en “Provider” aunque nuestro servicio sólo se llama “remoteResource”.

El provider

Ahora vamos a definir el provider

function RemoteResourceProvider() {
  var _baseUrl;
  this.setBaseUrl=function(baseUrl) {
    _baseUrl=baseUrl;
  }
  this.$get=['$http',function($http) {
    return new RemoteResource($http,_baseUrl);
  }];
}

app.provider("remoteResource",RemoteResourceProvider);

La clase del propio servicio

Por último nos queda definir la propia clase que implementa el servicio que hemos llamado RemoteResource.

Esta clase tiene un único método llamado get. Este método acepta como parámetros dos funciones de callback . La primera función se llamará si se han podido obtener los datos y tiene como parámetro los datos obtenidos. La segunda función se llamará si ha habido algún error y tiene como parámetros los datos obtenidos y el estado HTTP.

function RemoteResource($http,baseUrl) {
  this.get=function(fnOK,fnError) {
        $http({
          method: 'GET', 
          url: baseUrl+'/datos.json'
        }).success(function(data, status, headers, config) {
            fnOK(data);
        }).error(function(data, status, headers, config) {
            fnError(data,status);
        });
      }
}

El controlador

Por último nos queda ver cómo queda el controlador al usar el nuevo servicio.

app.controller("SeguroController",['$scope','remoteResource',function($scope,remoteResource) {
  $scope.seguro={
    nif:"",
    nombre:"",
    ape1:"",
    edad:undefined,
    sexo:"",
    casado:false,
    numHijos:undefined,
    embarazada:false,
    coberturas: {
      oftalmologia:false,
      dental:false,
      fecundacionInVitro:false
    },
    enfermedades:{
      corazon:false,
      estomacal:false,
      rinyones:false,
      alergia:false,
      nombreAlergia:""
    },
    fechaCreacion:new Date()
  }
  
  remoteResource.get(function(seguro) {
    $scope.seguro=seguro;
  },function(data,status) {
    alert("Ha fallado la petición. Estado HTTP:"+status);
  });
  
}]);

Ejemplo

El código completo del ejemplo es el siguiente:

<!DOCTYPE html>
<html ng-app="app">
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body ng-controller="SeguroController">
    <form>
      <fieldset>
        <legend>Seguro Médico</legend>
          <label for="nif">NIF:</label><input id="nif" name="nif" type="text" ng-model="seguro.nif" /><br>
          <label for="nombre">Nombre:</label><input id="nombre" name="nombre" type="text" ng-model="seguro.nombre" /><br>
          <label for="ape1">1º Apellido:</label><input id="ape1" name="ape1" type="text" ng-model="seguro.ape1" /><br>
          <label for="edad">Edad:</label><input id="edad" name="edad" type="text" ng-model="seguro.edad" /><br>
          <label for="sexo">Sexo:</label><select id="sexo" name="sexo" type="checkbox" ng-model="seguro.sexo" ><option value="">--Elige opcion--</option><option value="H">Hombre</option><option value="M">Mujer</option></select><br>
          <label for="casado">Casado:</label><input id="casado" name="casado" type="checkbox" ng-model="seguro.casado" /><br>
          <label for="numHijos">Nº Hijos:</label><input id="numHijos" name="numHijos" type="text" ng-model="seguro.numHijos" /><br>
          <label for="embarazada">Embarazada:</label><input id="embarazada" name="embarazada" type="checkbox" ng-model="seguro.embarazada" /><br>
          <label for="fechaCreacion">Fecha de creaci&oacute;n:</label><input id="fechaCreacion" name="fechaCreacion" type="text" ng-model="seguro.fechaCreacion" /><br>
      </fieldset>
      <fieldset>
        <legend>Coberturas</legend>
          <label for="oftalmologia">Oftalmologia:</label><input id="oftalmologia" name="oftalmologia" type="checkbox" ng-model="seguro.coberturas.oftalmologia" /><br>
          <label for="dental">Dental:</label><input id="dental" name="dental" type="checkbox" ng-model="seguro.coberturas.dental" /><br>
          <label ng-show="seguro.sexo==='M'" for="fecundacionInVitro">Fecundacion In Vitro:</label><input ng-show="seguro.sexo==='M'" id="fecundacionInVitro" name="fecundacionInVitro" type="checkbox" ng-model="seguro.coberturas.fecundacionInVitro" /><br>
      </fieldset>      
      <fieldset>
      <legend>Enfermedades</legend>
          <label for="corazon">Corazon:</label><input id="corazon" name="corazon" type="checkbox" ng-model="seguro.enfermedades.corazon" /><br>
          <label for="estomacal">Estomacal:</label><input id="estomacal" name="estomacal" type="checkbox" ng-model="seguro.enfermedades.estomacal" /><br>
          <label for="rinyones">Ri&ntilde;ones:</label><input id="rinyones" name="rinyones" type="checkbox" ng-model="seguro.enfermedades.rinyones" /><br>
          <label for="alergia">Alergia:</label><input id="alergia" name="alergia" type="checkbox" ng-model="seguro.enfermedades.alergia" /><br>
          <label for="nombreAlergia">Nombre de la alergia:</label><input ng-disabled="seguro.enfermedades.alergia===false" id="nombreAlergia" name="nombreAlergia" type="text" ng-model="seguro.enfermedades.nombreAlergia" /><br>
      </fieldset> 
    </form>
  </body>
</html>

var app = angular.module("app", []);

function RemoteResource($http,baseUrl) {
  this.get=function(fnOK,fnError) {
        $http({
          method: 'GET', 
          url: baseUrl+'/datos.json'
        }).success(function(data, status, headers, config) {
            fnOK(data);
        }).error(function(data, status, headers, config) {
            fnError(data,status);
        });
      }
}

function RemoteResourceProvider() {
  var _baseUrl;
  this.setBaseUrl=function(baseUrl) {
    _baseUrl=baseUrl;
  }
  this.$get=['$http',function($http) {
    return new RemoteResource($http,_baseUrl);
  }];
}

app.provider("remoteResource",RemoteResourceProvider);



app.constant("baseUrl", ".");
app.config(['baseUrl', 'remoteResourceProvider',function(baseUrl, remoteResourceProvider) {
    remoteResourceProvider.setBaseUrl(baseUrl);
}]);


app.controller("SeguroController", ['$scope', 'remoteResource',function($scope, remoteResource) {
    $scope.seguro = {
      nif: "",
      nombre: "",
      ape1: "",
      edad: undefined,
      sexo: "",
      casado: false,
      numHijos: undefined,
      embarazada: false,
      coberturas: {
        oftalmologia: false,
        dental: false,
        fecundacionInVitro: false
      },
      enfermedades: {
        corazon: false,
        estomacal: false,
        rinyones: false,
        alergia: false,
        nombreAlergia: ""
      },
      fechaCreacion: new Date()
    }

    remoteResource.get(function(seguro) {
      $scope.seguro = seguro;
    }, function(data, status) {
      alert("Ha fallado la petición. Estado HTTP:" + status);
    });

  }
]);

Malas prácticas

En muchos ejemplos que se ven de AngularJS se tiende a definir un provider en un único bloque en vez de definir diversas funciones separadas como hemos hecho aqui.

Podemos ver el siguiente trazo de código en el que se ha definido el provider usando varias funciones anónimas anidadas.

app.provider("remoteResource", function() {
  var _baseUrl;
  this.setBaseUrl = function(baseUrl) {
    _baseUrl = baseUrl;
  }
  this.$get = ['$http',
    function($http) {
      return new function($http, baseUrl) {
        this.get = function(fnOK, fnError) {
          $http({
            method: 'GET',
            url: baseUrl + '/datos.json'
          }).success(function(data, status, headers, config) {
            fnOK(data);
          }).error(function(data, status, headers, config) {
            fnError(data, status);
          });
        }
      }($http, _baseUrl);
    }
  ];
});

Este código - aunque funciona - no es recomendable por lo complejo que resulta de entender.

Referencias