title: Returning Data from Service to Controller with Asynchronous Callback
body: <p>I'm trying to <strong>upload</strong> image from Camera or gallery. I <strong>wrote</strong> all the code in the service. The controller must receive the complete url from the camera or gallery to show it in a slide box, but now nothing receive.</p>
  
  <p>Everything works, but I couldn't send back to the controller the url of the image. I think the error is because I'm trying to return the value before that the function "obtenerImagen" execute.</p>
  
  <p>I'm trying to implement <strong>Callbacks</strong>, but I think I did not implemented correctly.</p>
  
  <p>The variable that I want to return with the url of the image is <strong>urlImagen</strong></p>
  
  <p>This is my <strong>controller</strong> that calls the service:</p>
  
  <pre><code> //generar el popup para seleccionar el origen de la imagen: cámara o galería
      function seleccionarImagen() {
          cambiarImagenesService.seleccionarImagen()
              .then(reemplazarImagen);
      }
  </code></pre>
  
  <p>And the service:</p>
  
  <pre><code>(function() {
  'use strict';
  
  angular
      .module('example.cambiarimagenes')
      .factory('cambiarImagenesService', cambiarImagenesService);
  
  cambiarImagenesService.$inject = ['remoteDataService','$q', '$ionicPopup','$cordovaCamera', '$cordovaFile', '$cordovaFileTransfer', '$cordovaDevice', '$rootScope'];
  
  /* @ngInject */
  function cambiarImagenesService(remoteDataService,$q, $ionicPopup, $cordovaCamera, $cordovaFile,  $cordovaFileTransfer, $cordovaDevice, $rootScope){ 
      var dias = [];
      var mensaje = '';
      var image = null;
      var urlImagen = '';
      var service = {
          obtenerHorariosComplejo: obtenerHorariosComplejo,
          seleccionarImagen: seleccionarImagen
      };
      return service;
  
      //cargar una nueva imagen
      function seleccionarImagen() {
          var popup = seleccionarImagenPopup();
          return $ionicPopup.show(popup).then(function(result) {
              if (result == -1) {
                  return false;
              }
              return urlImagen;
          });
      }
  
      function obtenerImagen(sourceType, callback){
          var options = {
              callback: callback,
              quality: 100,
              destinationType: Camera.DestinationType.FILE_URI,
              sourceType: sourceType,
              saveToPhotoAlbum: false
          };
  
          $cordovaCamera.getPicture(options).then(function(imagePath) {
              // Grab the file name of the photo in the temporary directory
              var currentName = imagePath.replace(/^.*[\\\/]/, '');
  
              //Create a new name for the photo
              var d = new Date(),
              n = d.getTime(),
              newFileName =  n + ".jpg";
  
              // If you are trying to load image from the gallery on Android we need special treatment!
              if ($cordovaDevice.getPlatform() == 'Android' &amp;&amp; sourceType === Camera.PictureSourceType.PHOTOLIBRARY) {
                  window.FilePath.resolveNativePath(imagePath, function(entry) {
                      window.resolveLocalFileSystemURL(entry, success, fail);
                      function fail(e) {
                          console.error('Error: ', e);
                      }
                      function success(fileEntry) {
                          var namePath = fileEntry.nativeURL.substr(0, fileEntry.nativeURL.lastIndexOf('/') + 1);
                          // Only copy because of access rights
                          $cordovaFile.copyFile(namePath, fileEntry.name, cordova.file.dataDirectory, newFileName).then(function(success){
                              image = cordova.file.dataDirectory + newFileName;
                              urlImagen = image;
                          }, function(error){
                              $scope.showAlert('Error', error.exception);
                          });
                      };
                  }
                  );
              } else {
                  var namePath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
                  // Move the file to permanent storage
                  $cordovaFile.moveFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(function(success){
                      image = cordova.file.dataDirectory + newFileName;
                      urlImagen = image;
                  }, function(error){
                      $scope.showAlert('Error', error.exception);
                  });
              }
          },
          function(err){
              console.log("error en el serivicio o cancelacion:"+err);
              // Not always an error, maybe cancel was pressed...
          })
      }
  
      //poopup para cargar nuevo imagen
      function seleccionarImagenPopup() {
          var scope = $rootScope.$new();
          scope.data = {
              tipo: null
          };
          return {
              templateUrl: 'scripts/complejo/agenda/nuevo-turno.html',
              title: "¿De dónde desea obtener la imagen?",
              scope: scope,
              buttons: [{
                  text: 'Cancelar',
                  onTap: function(e) {
                      scope.tipo = -1
                      return scope.tipo;
                  }
              }, {
                  text: '&lt;b&gt;Cámara&lt;/b&gt;',
                  type: 'button-positive',
                  onTap: function(e) {
                      scope.tipo = Camera.PictureSourceType.CAMERA;
                      obtenerImagen(scope.tipo, function(val){
                          urlImagen = val;
                      });
                      console.log("el valor de la imagen al tocar la camara es:"+image);
                      return urlImagen;
                  }
              }, {
                  text: '&lt;b&gt;Galería&lt;/b&gt;',
                  type: 'button-positive',
                  onTap: function(e) {
                      scope.tipo = Camera.PictureSourceType.PHOTOLIBRARY;
                      obtenerImagen(scope.tipo, function(val){
                          urlImagen = val;
                      });
                      console.log("el valor de la imagen al tocar la galeria es:"+image);
                      return urlImagen;
                  }
              }]
          };
      }
  
      //generar error si hubo un problema
      function generarError(e){
          console.log("error!!!!!!:"+e);
          if (e.message) {
              return $q.reject(e.message);
          }
          return $q.reject('Ups! Hubo un problema al conectarse al servidor.');
      }
  
  }
  })();
  </code></pre>
  
  <p><strong>Thanks for helping me!</strong></p>
  
  <p>//<strong>EDIT</strong>//</p>
  
  <p>This is now my service:</p>
  
  <pre><code>(function() {
  'use strict';
  
  angular
  .module('example.cambiarimagenes')
  .factory('cambiarImagenesService', cambiarImagenesService);
  
  cambiarImagenesService.$inject = ['remoteDataService','$q', '$ionicPopup','$cordovaCamera', '$cordovaFile', '$cordovaFileTransfer', '$cordovaDevice', '$rootScope'];
  
  /* @ngInject */
  function cambiarImagenesService(remoteDataService,$q, $ionicPopup,$cordovaCamera, $cordovaFile,  $cordovaFileTransfer, $cordovaDevice, $rootScope){ 
  var dias = [];
  var mensaje = '';
  var image = null;
  var urlImagen = '';
  var service = {
      obtenerHorariosComplejo: obtenerHorariosComplejo,
      seleccionarImagen: seleccionarImagen
  };
  return service;
  
  //cargar una nueva imagen
  function seleccionarImagen() {
      var popup = seleccionarImagenPopup();
      return $ionicPopup.show(popup).then(function(result) {
          if (result == -1) {
              return false;
          }
          return urlImagen;
      });
  }
  
  function obtenerImagen(sourceType){
      var options = {
          quality: 100,
          destinationType: Camera.DestinationType.FILE_URI,
          sourceType: sourceType,
          saveToPhotoAlbum: false
      };
  
      return $cordovaCamera.getPicture(options).then(function(imagePath) {
          // Grab the file name of the photo in the temporary directory
          var currentName = imagePath.replace(/^.*[\\\/]/, '');
  
          //Create a new name for the photo
          var d = new Date(),
          n = d.getTime(),
          newFileName =  n + ".jpg";
  
          // If you are trying to load image from the gallery on Android we need special treatment!
          if ($cordovaDevice.getPlatform() == 'Android' &amp;&amp; sourceType === Camera.PictureSourceType.PHOTOLIBRARY) {
              window.FilePath.resolveNativePath(imagePath, function(entry) {
                  window.resolveLocalFileSystemURL(entry, success, fail);
                  function fail(e) {
                      console.error('Error: ', e);
                  }
                  function success(fileEntry) {
                      var namePath = fileEntry.nativeURL.substr(0, fileEntry.nativeURL.lastIndexOf('/') + 1);
                      // Only copy because of access rights
                      $cordovaFile.copyFile(namePath, fileEntry.name, cordova.file.dataDirectory, newFileName).then(function(success){
                          image = cordova.file.dataDirectory + newFileName;
                          return image;
  
                      }, function(error){
                          $scope.showAlert('Error', error.exception);
                      });
                  };
              }
              );
          } else {
              var namePath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
              // Move the file to permanent storage
              $cordovaFile.moveFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(function(success){
                  image = cordova.file.dataDirectory + newFileName;
                  return image;
              }, function(error){
                  $scope.showAlert('Error', error.exception);
              });
          }
      },
      function(err){
          console.log("error en el serivicio o cancelacion:"+err);
          // Not always an error, maybe cancel was pressed...
      })
  }
  
  //poopup para cargar nuevo imagen
  function seleccionarImagenPopup() {
      var scope = $rootScope.$new();
      scope.data = {
          tipo: null
      };
      return {
          templateUrl: 'scripts/complejo/agenda/nuevo-turno.html',
          title: "¿De dónde desea obtener la imagen?",
          scope: scope,
          buttons: [{
              text: 'Cancelar',
              onTap: function(e) {
                  scope.tipo = -1
                  return scope.tipo;
              }
          }, {
              text: '&lt;b&gt;Cámara&lt;/b&gt;',
              type: 'button-positive',
              onTap: function(e) {
                  scope.tipo = Camera.PictureSourceType.CAMERA;
                  var promise = obtenerImagen(scope.tipo)
                  .then(function(val){
                      // asignamos el valor asincrónico
                      urlImagen = val;
                      // retornamos el valor a la cadena
                      return val;
                  });
                  // retornamos la promesa de manera síncrona
                  return promise;
              }
          }, {
              text: '&lt;b&gt;Galería&lt;/b&gt;',
              type: 'button-positive',
              onTap: function(e) {
                  scope.tipo = Camera.PictureSourceType.PHOTOLIBRARY;
                  var promise = obtenerImagen(scope.tipo)
                  .then(function(val){
                      // asignamos el valor asincrónico
                      urlImagen = val;
                      // retornamos el valor a la cadena
                      return val;
                  });
                  // retornamos la promesa de manera síncrona
                  return promise;
              }
          }]
      };
  }
  
  //generar error si hubo un problema
  function generarError(e){
      console.log("error!!!!!!:"+e);
      if (e.message) {
          return $q.reject(e.message);
      }
      return $q.reject('Ups! Hubo un problema al conectarse al servidor.');
  }
  
  }
  })();
  </code></pre>