title: Angular, ionic, Service promise, deferred, async
body: <p>I am trying to use a <code>service</code> that runs an asynchronous function.
  I am trying to call the factory, then do something only it is resolved.
  But it doesn't work, I get the error : <code>Uncaught TypeError: Cannot read property 'then' of undefined</code></p>
  
  <p>I am declaring the deferred object into the service function and I return its promise.</p>
  
  <p>Can you help me please ?</p>
  
  <p>app.js:</p>
  
  <pre><code>angular.module('SnowBoard', ['ionic', 'ngCookies', 'ui.unique', 'SnowBoard.controllers', 'SnowBoard.services'])
  
  .run(["isPhoneGap","connectionStatus", 'updateProDB', "$ionicPlatform", '$q', 'sessionService', 'imagesService', function(isPhoneGap, connectionStatus, updateProDB, $ionicPlatform, $q, sessionService, imagesService) {
    $ionicPlatform.ready(function() {
      // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
      // for form inputs)
      if(window.cordova &amp;&amp; window.cordova.plugins.Keyboard) {
        cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      }
      if(window.StatusBar) {
        // org.apache.cordova.statusbar required
        StatusBar.styleDefault();
      }
    });
  
  
    var promise = updateProDB.get();
    promise.then(
            function(data) { 
                imagesService.checkIfImagesExistAllAtOnce(prodata);
            },
            function(error) {
  
            });
  }])
  </code></pre>
  
  <p>service.js:</p>
  
  <pre><code>.service('updateProDB', ['isPhoneGap', 'connectionStatus', 'isIOS', '$q', 'sessionService', function updateProDBFactory(isPhoneGap, connectionStatus, isIOS, $q, sessionService) {
      this.get = function(){
  
          var debugOptionUseLocalDB=0;
          var prodata=[];
          var gotANewDB;
          var dbReadyDeferred = $q.defer();
  
          if (typeof debugOptionUseLocalDB != 'undefined' &amp;&amp; debugOptionUseLocalDB) {
              fallbackToLocalDBfile();
              return dbReadyDeferred.promise;
              gotANewDB = 1;
              console.log('on a fini fallbackToLocalDBfile, et dbReadyDeferred.state()='+dbReadyDeferred.state());
          }else{
              if(connectionStatus == 'online'){
                  console.log("reaching DB on server (getJsonpFile)...");
  
                  getDBfileXHR(dbUrl()).then(function(){ //if resolved
                          console.log(prodata);
                          return dbReadyDeferred.promise;
                      }, function (){ // if rejected
                          console.log("...basic XHR request failed, falling back to local DB file...and sending mail to dev.");
                          fallbackToLocalDBfile();
                          return dbReadyDeferred.promise;
                          var body = ""; 
                          if ( isPhoneGap ) {
                              body += " Platform : phonegap";
                              body += " device.cordova : "+device.cordova;
                              body += " device.model : "+device.model;
                              body += " device.name : "+device.name;
                              body += " device.platform : "+device.platform;
                              body += " device.uuid : "+device.uuid;
                              body += " device.version : "+device.version;
                          } else {
                              body += "Platform : not phonegap -&gt; web browser"
                              body += "navigator.userAgent : "+navigator.userAgent;
                          }
                          var data={
                                  userEmail: "louisromain@yahoo.fr",
                                  subject: "BoardLine dev issue: had to fallback to local DB file",
                                  destEmail: "louisromain@yahoo.fr",
                                  body: body           
                                 }
                          sendToServer(data).done(funcSuccess).fail(funcError);
                          function funcSuccess(data /* , textStatus, jqXHR */ ) {
                              console.log("Message to dev successfully sent");
                          }
                          function funcError(data , textStatus, jqXHR  ) {
                              console.log("The message to dev could not be sent...");
                          }
                      });
  
  
              }else{ //offline
                  console.log('device is offline');
                  if(localStorage) {
                      if ( isPhoneGap || !isIOS() ) { //BUG iOS safari doesn't work with this (Cf. Philippe's ipad)
                          if (localStorage.getItem("proDB") === null ) { //if proDB exists in localStorage
                              fallbackToLocalDBfile();
                          } else {
                              //popShortToast("...reading DB in localStorage.");
                              var data = JSON.parse(localStorage["proDB"]); //read current localstorage
                              prodata = storeJsonInProdata(data);
                              sessionService.store('prodata', prodata);
                              dbReadyDeferred.resolve(); //initializeSelectButtons();
                              return dbReadyDeferred.promise;
                          }
                      }
                  }else{ //if localStorage not available, read local file
                      prodata = fallbackToLocalDBfile();
                      return dbReadyDeferred.promise;
                  }
              }
          }
  
          function getDBfileXHR(url) {
              var getDBfileXHRdeferred = $q.defer();
              var request = new XMLHttpRequest();
              request.open("GET", url, true); //3rd parameter is sync/async
              request.timeout = 2000;
              //console.log(url);
              request.onreadystatechange = function() {      //Call a function when the state changes.
                 if (request.readyState == 4) {
                    if (request.status == 200 || request.status == 0) { 
                       console.log('we get a response from XHR');
                       //popShortToast("...updating DB from server using simple XHR.");
                       var jsonText = request.responseText.replace("callback(", "").replace(");", "");
                       prodata = storeJsonInProdata(JSON.parse(jsonText));
                       sessionService.store('prodata', prodata);
                       // console.log(prodata);
                       gotANewDB = 1; 
                       getDBfileXHRdeferred.resolve();
                       dbReadyDeferred.resolve();
                    } else {
                      console.log('error : request.status = '+request.status);
                      getDBfileXHRdeferred.reject();
                    }
                 }
              }
              console.log("Sending XMLHttpRequest...");
              request.send();
              return getDBfileXHRdeferred.promise;
          }
          function dbUrl(){
              return unescape(encodeURIComponent("http://user:pass@boardlineapp.com/app/proDB.jsonp")); //JSONP
          }
          function fallbackToLocalDBfile(){
              getDBfileXHR('proDB.jsonp').then(function(){ //if resolved
                          console.log(prodata);
                          return dbReadyDeferred.promise;
                      });
          }
      }
  
      function sendToServer(dataToSend) {
          return $.ajax({
              url: 'http://aurel:aurel40@boardlineapp.com/app/mail.php',
              type: "POST",
              dataType: "xml",
              data: dataToSend
          });
      }
      function storeJsonInProdata(data) { //function to store the DB json file into a variable prodata usable in the whole app
          console.log("storing json in prodata");
          //clear prodata first
          var prodata=[];
          //if JSON
          var lines=[];
          for(var i = 0; i &lt;= data.length; i++){
              lines[i]=data[i];
          }
          var fieldnames=lines[0];
          //if tab separated TXT with each model on a separate line
          //      var lines=data.split(/\n/);
          //      var fieldnames=lines[0].split(/\t/);
          var i;
          prodata.push(lines[0]);
          //prodata.push(0);
          for (i = 1; i &lt; lines.length-1; ++i) {
              //if JSON
              var fields=lines[i];
              //if TXT            
              //          var fields=lines[i].split(/\t/);
              //prodata.push(i);          
              var j;
              prodata[i]={};
              prodata[i]['id']=i; //auto id, there is no more 'id' column in the DB file.
              for (j = 0; j &lt; fields.length; ++j) {
                  var str=fieldnames[j];
                  prodata[i][str]=fields[j];  
              }
          }
          return prodata;
      }
  
  }]);
  </code></pre>