Reputation: 10589
I'm trying to build a database in my angular factory:
angular.module("App")
.factory("DatabaseFactory", function () {
var database = null;
var factory = {};
factory.getDatabase = function () {
if (database == null) {
window.sqlitePlugin.openDatabase({
name: "myDB.db",
androidDatabaseImplementation: 2,
androidLockWorkaround: 1
}, function (db) {
database = db;
database.transaction(function (transaction) {
transaction.executeSql(create_user, [], function (transaction, result) {
console.log("table user created: " + JSON.stringify(result));
}, function (error) {
console.log("table user error: " + error.message);
});
}, function (error) {
console.log("transaction error: " + error.message);
}, function () {
console.log("transaction ok");
return database;
});
});
} else {
return database;
}
}
return factory;
});
The creation of the database works, the transaction is also ok. I now provide a service with a function to init the database:
angular.module("App")
.service("DatabaseService", function (DatabaseFactory) {
var database;
function initDatabase() {
console.log("init before database: " + JSON.stringify(database));
database = DatabaseFactory.getDatabase();
console.log("intit after database: " + JSON.stringify(database));
}
return {
initDatabase: function () {
initDatabase();
}
};
});
It gets called on device ready:
angular.module("App", ["ionic", "ngCordova", "App.Home"])
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("app", {
url: "/app",
abstract: true,
templateUrl: "templates/main.html"
});
$urlRouterProvider.otherwise("/app/home");
})
.run(function ($rootScope, $ionicPlatform, DatabaseService) {
$ionicPlatform.ready(function () {
console.log("ionic Ready");
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
StatusBar.styleDefault();
}
DatabaseService.initDatabase();
});
});
The log output:
init before database: + undefined
init after database: + undefined
So the return of the database in my factory returns undefined, but I don't know why. It should return the database since it is correctly initialized.
Upvotes: 0
Views: 243
Reputation: 29989
You can't return the database from the function, because the function that receives it is an asynchronous callback.
You can only use the return
statement if the entire function is synchronous (e.g. doesn't do any async work, such as reading from files, connecting to databases, network requests, sockets etc).
In your case, window.sqlitePlugin.openDatabase
does some asynchronous work and asks for a callback as the second argument. This callback will be called after the database connection has opened, which will be after your getDatabase
function has returned a value.
window.sqlitePlugin.openDatabase({
name: "myDB.db",
androidDatabaseImplementation: 2,
androidLockWorkaround: 1
}, function (db) {
database = db
// this happens at some point in the future
});
// this happens straight away
// at this point database is still undefined
return database;
A good way to test this for future reference is to use console.log
to see at what time and in what order your code is run.
window.sqlitePlugin.openDatabase({
// ...
}, function (db) {
database = db
console.log('A');
});
console.log('B');
return database;
You would see that rather than being executed in the order the statements are written, B
is logged first, then A
second.
If you make your getDatabase
method take a callback argument, you can pass the db
object into it as soon as it is ready.
factory.getDatabase = function (callback) {
window.sqlitePlugin.openDatabase({
// ...
}, function (db) {
// do some stuff with db, when you are ready
// pass it to the callback, with null as the
// first argument (because there isn't an error
callback(null, db);
});
Then you would rewrite your code to make use of the callback.
DatabaseFactory.getDatabase(function(err, db) {
console.log("intit after database: " + JSON.stringify(database));
});
You might be wondering why the callback has an err
argument too.
In node.js, it is considered standard practice to handle errors in asynchronous functions by returning them as the first argument to the current function's callback. If there is an error, the first parameter is passed an Error object with all the details. Otherwise, the first parameter is null.
(From NodeJitsu)
Upvotes: 1
Reputation: 13
I think you should replace
var database = null;
var factory = {};
by
var factory = {};
and do
return factory.database
in your factory.getDatabase
Upvotes: 0