Angular/Ionic and async SQLite - ensuring data factory initialised before return Angular/Ionic and async SQLite - ensuring data factory initialised before return angularjs angularjs

Angular/Ionic and async SQLite - ensuring data factory initialised before return


Managed to get it working in the end. Posting this here for anyone else having the issue.

dataFactory.js

  • Reworked all private methods using async SQL calls in dataFactory.js to return promises
  • Created a public initDB method which chained calls to the private methods (e.g. openDB >> dropTable_ >> createTable_ etc). Also returned a promise (empty)
  • Returned initDB and getAllItems() from the factory immediately

    .factory('dataFactory', [function($window, $log, $q, $cordovaSQLite, dummyDataGenerator){      var db_;  // private methods - all return promises  var openDB_ = function(dbName){    var q = $q.defer();    // ...call async SQL methods    return q.promise;  };  var createTable_ = function(){    var q = $q.defer();    // ...call async SQL methods    return q.promise;                 };  // ...etc  // public methods  var initDB = function(){    var q = $q.defer();    // successively call private methods, chaining to next with .then()    openDB_("myDB").then(function(db){      var schema = "...SQL schema here..."      dropTable_(db, "FirstTable", schema).then(function(tableName){        // ...etc        // when all done, resolve the promise        q.resolve();      })    })    return q.promise;  }  var getAllItems = function(){    var q = $q.defer();    // ...call async SQL methods    return q.promise;  };  return {    initDB: initDB,    getAllItems: getAllItems   };]}); // <-- factory

app.js

  • Used the resolve ability of ui-router
  • My previous attempts had not correctly injected promises
  • Added a resolve to the top-level abstract state to fire off the call to initDB
  • Injected the promise from initDB to the child state's resolve object
  • Inject the resolve object into the controller

    // APP ROUTING (using ui-router) .config(function($stateProvider, $urlRouterProvider){

    $stateProvider  // top-level abstract state that houses Ionic side menu & nav  .state('app', {    url: '/app',    abstract: true,    templateUrl: "templates/sideMenu.html",    resolve: {      dbReady: function($log, dataFactory){        // (1) init the DB        return dataFactory.initDB().then(function(){          $log.log("initDB promise resolved");      });    }  }})// the following states are all child states of app.state('app.items', {  url: "/items",  views: {    menuContent: {      templateUrl: "templates/gbCaseList.html",      // (3) now we can inject the items promise into our controller      controller: function($scope, $log, items){        // (4) uses resolved items variable injected by ui-router        $scope.allItems = items;      }    }  },  resolve: {    // (2) note that we MUST inject the dbReady promise, if we don't this will instantiate immediately    items: function(dbReady, $log, dataFactory){      // the following call returns a promise      return dataFactory.getItems();    }  }})

All working now. Massive thanks to this post for clearing up my use of ui-router Run controllers only after initialization is complete in AngularJS