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

后端 未结 1 1554
耶瑟儿~
耶瑟儿~ 2021-02-09 00:23

I\'m writing a PhoneGap/Cordova app with Ionic, and using SQLite (with ngCordova) for persistent storage. The core of the app is a scrolling list of items which are retrieved fr

1条回答
  •  爱一瞬间的悲伤
    2021-02-09 00:37

    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

    0 讨论(0)
提交回复
热议问题