title: Trying to get an async DB request to work in Angular, "Cannot call method then of undefined"
body: <p>I'm building a PhoneGap app using AngularJS + an SQLite database. I am having a classic "How does asynchronous work" Angular problem with a database query, getting error "Cannot call method then of undefined". I am hoping someone can help me to see the error of my ways.</p>
  
  <p>Here's my query function. Every alert() in here returns meaningful data indicating that the transaction itself is successful:  </p>
  
  <pre><code>    .factory('SQLService', ['$q', '$rootScope', 'phonegapReady',
          function ($q, $rootScope, phonegapReady) {
  
          function search(query) {
              alert("Search running with " + query);
  
              var promise = db.transaction(function(transaction) {
  
                  var str = "SELECT category, id, chapter, header, snippet(guidelines, '&lt;b&gt;', '&lt;/b&gt;', '...', '-1', '-24' ) AS snip FROM guidelines WHERE content MATCH '" + query + "*';";
  
                  transaction.executeSql(str,[], function(transaction, result) {
                      var resultObj = {},
                          responses = [];
                      if (result != null &amp;&amp; result.rows != null) {
                          for (var i = 0; i &lt; result.rows.length; i++) {
                              resultObj = result.rows.item(i);
                              alert(resultObj.category); //gives a meaningful value from the DB
                              responses.push(resultObj);
                          }
                      } else {
                          //default content
                      }
  
                  },defaultNullHandler,defaultErrorHandler);
                  alert("End of transaction");
              });
              // Attempting to return the promise to the controller
              alert("Return promise"); //this alert happens
              return promise;
  
          }
  
           return {
              openDB : openDB,
              search: search
           };
       }]);
  </code></pre>
  
  <p>And in my controller, which gives the "Cannot call method then of undefined" error: </p>
  
  <pre><code>       $scope.search = function(query) {
  
              SQLService.search(query).then(function(d) {
                  console.log("Search THEN"); //never runs
                  $scope.responses = d; //is never defined
              });
  
          }
  </code></pre>
  
  <hr>
  
  <p>Thanks to the accepted answer, here is the full working code. </p>
  
  <h1>Service</h1>
  
  <pre><code>  function search(query) {
              var deferred = $q.defer();
  
              db.transaction(function(transaction) {
  
                  var str = "SELECT category, id, chapter, header, snippet(guidelines, '&lt;b&gt;', '&lt;/b&gt;', '...', '-1', '-24' ) AS snip FROM guidelines WHERE content MATCH '" + query + "*';";
                  transaction.executeSql(str,[], function(transaction, result) {
                      var resultObj = {},
                          responses = [];
                      if (result != null &amp;&amp; result.rows != null) {
                          for (var i = 0; i &lt; result.rows.length; i++) {
                              resultObj = result.rows.item(i);
                              responses.push(resultObj);
                          }
                      } else {
                          resultObj.snip = "No results for " + query;
                          responses.push(resultObj)
                      }
  
                      deferred.resolve(responses); //at the end of processing the responses
                  },defaultNullHandler,defaultErrorHandler);
              });
  
              // Return the promise to the controller
              return deferred.promise;
  
          }
  </code></pre>
  
  <h1>Controller</h1>
  
  <pre><code>$scope.search = function(query) {
  
              SQLService.search(query).then(function(d) {
                  $scope.responses = d;
              });
  
          }
  </code></pre>
  
  <p>I can then access the responses in the template using $scope.responses.</p>