我正在使用Ionic编写PhoneGap / Cordova应用程序,并使用SQLite(使用ngCordova)进行持久存储。应用程序的核心是从SQLite数据库中检索的项目的滚动列表。
listController.js
.controller('ListCtrl', [
'$scope',
'dataFactory',
function($scope, dataFactory) {
var items = dataFactory.getAllItems().then(function(data){
$scope.allItems = data;
});
}
]);
dataFactory.js
.factory('dataFactory', [function($window, $log, $q, $cordovaSQLite, dummyDataGenerator){
var db_;
// ...lots of SQLite fun in here
// cascading async callbacks to load the database and inject dummy data
var openDB_ = function(){...};
var createTable_ = function(){...};
// etc
var getAllItems = function(){
var q = $q.defer();
$cordovaSQLite.execute(db_, sqlSelectString, []).then(
function(results) {
$log.log("SQL SELECT successful");
var i, len, allItems = [];
for(i = 0, len = results.rows.length; i < len; i++) {
allItems.push(results.rows.item(i));
}
q.resolve(allItems);
},
function (err) {
q.reject(err);
}
);
return q.promise;
};
return { getAllItems: getAllItems };
]}); // <-- factory
最初,我马上回到了工厂。控制器在数据准备好之前运行getAllItems()
。该视图最初为空,仅在第二个getAllItems()
所以我尝试通过添加一个factoryReady()函数来延迟工厂的返回,并且只有在所有内部数据库内容都准备好后才调用它
var factoryReady = function(){
return {
getAllItems: getAllItems
};
};
现在有一个未定义的错误,因为整个工厂在第一次调用时不可用,而不是getAllItems()
只是空手而归。我可以看到SQL数据库在适当的时候正确写入,但Angular在完成之前会抛出异常。
我现在意识到这是可预测的,我已阅读帖子AngularJS : Initialize service with asynchronous data但不太了解如何实施排名靠前的答案(由joakimbl提供)
揭示服务的最佳方式是什么,并确保在内部异步内容完成之前控制器不会调用它?我是否需要将ENTIRE服务作为承诺而不仅仅是getAllItems
的结果返回?我有一个去,但现在我很困惑。感谢。
修改
我在加载视图http://blog.brunoscopelliti.com/show-route-only-after-all-promises-are-resolved时也考虑过使用ui-router的resolve
,但这并没有解决SQL数据/工厂的内部准备问题。如果我返回getAllCases
方法,那么它仍然会被立即调用,SQL数据库中没有任何内容,SQL查询返回一个空结果集,promise将解析并呈现视图。
答案 0 :(得分:7)
管理以使其最终运作。在这里发布此问题给其他有问题的人。
<强> dataFactory.js 强>
openDB
&gt;&gt; dropTable_
&gt;&gt; createTable_
等。还返回了一个承诺(空)立即从工厂返回initDB
和getAllItems()
.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 强>
resolve
功能
resolve
以触发对initDB
initDB
注入到子状态的resolve
对象将解析对象注入控制器
// APP ROUTING(使用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();
}
}
})
现在全部工作。非常感谢这篇文章清理我对ui-router Run controllers only after initialization is complete in AngularJS
的使用