Deferred then of then is undefined for IndexedDb - javascript

I'm using CanJs and I'm learning jquery deferred but I have a problem.
I created a controller as sort of Singleton to manage data in IndexedDb.
First of all, I created an openDb function like this:
openDbDeferred: null,
openDb: function (dbName, dbVersion) {
console.log('Open DB...');
var openDbDeferred = this.openDbDeferred;
if (!openDbDeferred || openDbDeferred.isRejected()) {
openDbDeferred = $.Deferred();
var db;
var req = indexedDB.open(dbName, dbVersion);
req.onsuccess = function (evt) {
db = this.result;
console.log('openDB SUCCESS');
openDbDeferred.resolve(db);
};
req.onerror = function (evt) {
console.error("[ERROR] openDb: " + evt);
openDbDeferred.reject();
};
req.onupgradeneeded = function (evt) {
console.log('openDb.onupgradeneeded');
var db = evt.target.result;
var store = db.createObjectStore('sessioni', {keyPath: 'idSession'});
store.createIndex('by_url', 'url', {unique: false});
store.createIndex('by_startDate', 'startDate', {unique: false});
store.createIndex('by_endDate', 'endDate', {unique: false});
};
}
return openDbDeferred.promise();
}
Then I created a function to retrieve all data in DB:
getFilesList: function () {
var getDataDeferred;
return this.openDb('session-db', 1).then(function (db) {
console.log('Find all records...');
getDataDeferred = $.Deferred();
var tx = db.transaction("sessioni", "readwrite");
var store = tx.objectStore("sessioni");
var items = [];
tx.oncomplete = function() {
//console.log(items);
getDataDeferred.resolve(items);
console.log('Transazione getFilesList completata');
};
tx.onfailure = function(evt) {
getDataDeferred.reject();
console.error('[ERROR] Transazione getFilesList fallita: ' + evt);
};
var cursorRequest = store.openCursor();
cursorRequest.onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor) {
items.push(cursor.value);
cursor.continue();
}
};
cursorRequest.onerror = function (error) {
console.error('findAll [ERROR]: ' + error);
};
});
return getDataDeferred.promise();
}
I declared this controller in another controller to call getFilesList function:
retreiveAllData: function() {
return this.sessionManageModel.getFilesList().than(function(items) {
console.log(items)
return items;
});
}
When the retreiveAllData function is called, it returns 'undefined' because items is 'undefined'.
How can I obtain items in retreiveAllData function?

You've got two return statements in your getFilesList function. The second one should actually be inside the then callback - which currently returns undefined as you observe.
getFilesList: function () {
// no need to declare deferred variable outside of the callback
return this.openDb('session-db', 1).then(function (db) {
var getDataDeferred = $.Deferred();
… // do all the stuff
return getDataDeferred; // place the `return` here
});
// not here!
}

Related

Class constructor property value is null

I am trying to use indexedDB for the first time and want to create a class for it. My code works opening the database and saving an object to it but when I try to retrieve the object it is null
var libraries = new storedLibraries();
libraries.openDb();
```
user action
```
libraries.saveLibrary(template);
Class.
class storedLibraries {
constructor() {
this.DB_NAME = 'recording-template';
this.DB_VERSION = 1;
this.DB_STORE_NAME = 'library';
this.db = null;
this.result = null;
if (!('indexedDB' in window)) {
console.log('This browser doesn\'t support IndexedDB');
return;
}
}
openDb() {
var request = indexedDB.open(this.DB_NAME, this.DB_VERSION);
var _self = this;
request.onsuccess = function (evt) {
_self.db = this.result;
_self.getObjectStore();
console.log(_self.result);
console.log("openDb DONE");
};
request.onerror = function (evt) {
console.error("openDb:", evt.target.errorCode);
};
request.onupgradeneeded = function (evt) {
console.log("openDb.onupgradeneeded");
var store = evt.currentTarget.result.createObjectStore(_self.DB_STORE_NAME, { keyPath: 'id', autoIncrement: true });
};
}
saveLibrary(template) {
var transaction = this.db.transaction(["library"], "readwrite");
// Do something when all the data is added to the database.
var _self = this;
transaction.oncomplete = function(event) {
console.log("All done!");
};
transaction.onerror = function(event) {
// Don't forget to handle errors!
};
var objectStore = transaction.objectStore("library");
var request = objectStore.add(template);
request.onsuccess = function(event) {
// event.target.result
};
}
getObjectStore() {
//console.log(this);
var transaction = this.db.transaction(["library"], "readwrite");
var objectStore = transaction.objectStore("library");
var request = objectStore.getAll();
var _self = this;
request.onerror = function(event) {
// Handle errors!
};
request.onsuccess = function(event) {
// Do something with the request.result!
_self.result = request.result;
console.log(_self.result);
};
}
}
The console.log(_self.result); in getObjectStore() outputs the correct value but in openDb() it is null. I have tried many different things but I am obviously not understanding something?
I got it to work using promises.
const libraries = new storedLibraries();
libraries.loadLibraries();
Class.
class storedLibraries {
constructor() {
this.DB_NAME = 'recording-template';
this.DB_VERSION = 1;
this.DB_STORE_NAME = 'library';
this.db = null;
this.libraries = [];
if (!('indexedDB' in window)) {
console.log('This browser doesn\'t support IndexedDB');
return;
}
}
loadLibraries() {
this.openDb().then((result) => {
this.getObjectStore().then((result) => {
for(const res of result) {
this.libraries.push(new recordingsTemplate(res));
}
});
}).catch(console.error);
}
async openDb() {
var _self = this;
const prom = new Promise((resolve, reject) => {
var request = indexedDB.open(_self.DB_NAME, _self.DB_VERSION);
request.onsuccess = (event) => {
console.log("openDb:");
_self.db = request.result;
resolve(request.result);
}
request.onerror = (event) => {
console.error("openDb:", event.target.errorCode);
reject(evt);
}
request.onupgradeneeded = (event) => {
console.log("openDb.onupgradeneeded");
_self.db = request.result;
var store = event.currentTarget.result.createObjectStore(_self.DB_STORE_NAME, { keyPath: 'id', autoIncrement: true });
var transaction = event.target.transaction;
transaction.oncomplete = (event) => {
resolve(store);
}
}
});
return prom;
}
async getObjectStore() {
var _self = this;
const prom = new Promise((resolve, reject) => {
var transaction = _self.db.transaction(["library"], "readwrite");
var objectStore = transaction.objectStore("library");
var request = objectStore.getAll();
request.onerror = (event) => {
// Handle errors!
reject(event);
};
request.onsuccess = (event) => {
resolve(request.result);
};
});
return prom;
}
async saveLibrary(template) {
var _self = this;
const prom = new Promise((resolve, reject) => {
var transaction = _self.db.transaction(["library"], "readwrite");
// Do something when all the data is added to the database.
transaction.oncomplete = function(event) {
console.log("All done!");
};
transaction.onerror = function(event) {
// Don't forget to handle errors!
};
var objectStore = transaction.objectStore("library");
var request = objectStore.add(template);
request.onsuccess = function(event) {
// event.target.result
};
});
return prom;
}
}

Ping site with knockout.js

I want to ping a few sites using javascript, and found this pen and does what I want.
However, I don't understand when I add goo12121212gle.com to the list of sites as a test it comes up saying that the domain has responded but in the console log I see ERR_NAME_NOT_RESOLVED??
I am new to JS but I am not sure why the below script is both saying the site is there and not at the same time? Is something missing from the script?
function ping(ip, callback) {
if (!this.inUse) {
this.status = 'unchecked';
this.inUse = true;
this.callback = callback;
this.ip = ip;
var _that = this;
this.img = new Image();
this.img.onload = function () {
_that.inUse = false;
_that.callback('online');
};
this.img.onerror = function (e) {
if (_that.inUse) {
_that.inUse = false;
_that.callback('offline', e);
}
};
this.start = new Date().getTime();
this.img.src = "http://" + ip;
this.timer = setTimeout(function () {
if (_that.inUse) {
_that.inUse = false;
_that.callback('timeout');
}
}, 1500);
}
}
var PingModel = function (servers) {
var self = this;
var myServers = [];
ko.utils.arrayForEach(servers, function (location) {
myServers.push({
name: location,
status: ko.observable('unchecked')
});
});
self.servers = ko.observableArray(myServers);
ko.utils.arrayForEach(self.servers(), function (s) {
s.status('checking');
new ping(s.name, function (status, e) {
s.status(e ? "error" : status);
});
});
};
var komodel = new PingModel(['goo12121212gle.com','msn.com','104.46.36.174','23.97.201.12']);
ko.applyBindings(komodel);
https://codepen.io/lyellick0506/pen/NGJgry
Both the onerror- and onload-callback use "responded" as the message, so there is no way to differentiate between them:
this.img.onerror = function (e) {
if (_that.inUse) {
_that.inUse = false;
_that.callback('responded', e); // <--- change this to a different message
}
};
Alternatively you could just check if the e parameter has been set:
new ping(s.name, function (status, e) {
s.status(e ? "error" : status);
});

How return var from callback function ? OOP property

var App = function(){
this.db = [];
}
App.prototype.getJson = function(){
var slef = this;
$.getJSON('url', function(data){
self.db.push(data);
});
}
$(document).ready(function(){
var app = new App();
console.log(app.db); //return []
setTimeout(function(){
console.log(app.db); //return data JSON
}, 5000);
});
Why is this happening? How get property app.db without setTimeout?
AND
Can i return variable from callback function without constriction
appAPI.db.async.get(key, function(value) {
var data = (value === null) ? null : JSON.parse(value);
// invoke the callback and pass the results to it
callback(data);
});
and
LB.getData('user', function(data) {
// use the data here
alert(data.someProperty);
});
?
it cause because you do assync request, use promices to get value after request is end. http://api.jquery.com/promise/
setTimeout(function(){
console.log(app.db); //return data JSON
}, 5000);
donot save you if request will be longer then 5sec
sample:
var App = function(){
this.db = [];
}
var dfd = new jQuery.Deferred();
App.prototype.getJson = function(){
var slef = this;
$.getJSON('url', function(data){
self.db.push(data);
dfd.resolve(data);
});
}
$(document).ready(function(){
var app = new App();
console.log(app.db); //return []
$.when( dfd.promise()).then(
function( data) {
console.log(app.db);
}
);
});

getting TypeError: Cannot call method 'then' of undefined in angularjs controller

I keep getting the error - TypeError: Cannot call method 'then' of undefined when i call a method (database.readOnlyStock()) in my factory. also what i find a little ackward is that the function then does run accordingly because i see the console.log messages.
here is the factory code:
stocks.factory('database', ['$resource', '$http', '$q', function($resource, $http, $q) {
var dataMethods = {
createConnection: function() {
/*moved to onload below */
},
addStock: function(stock, nameofcompany) {
var _this = this;
console.log("About to add stock");
//Get a transaction
//default for OS list is all, default for type is read
var transaction = this.db.transaction(["portfolio"],"readwrite");
//Ask for the objectStore
var store = transaction.objectStore("portfolio");
//Define a person
var stockTemplate = {
company_name: nameofcompany,
name:stock,
created:new Date()
}
//Perform the add
var request = store.add(stockTemplate);
request.onerror = function(e) {
console.log("failed to add stock to portflio",e.target.error.name);
//some type of error handler
}
request.onsuccess = function(e) {
console.log("successfully added stock to portfolio");
//console.log(store);
//_this.readOnlyStock();
}
},
readOnlyStock: function() {
var deferred = $q.defer();
var transaction = this.db.transaction(["portfolio"],"readonly");
var store = transaction.objectStore("portfolio");
// var cursorRequest = store.openCursor();
var arrayOfStocks = [];
var keyRange = IDBKeyRange.lowerBound(0);
var cursorRequest = store.openCursor(keyRange);
cursorRequest.onsuccess = function(e) {
var cursor = e.target.result;
if(cursor){
arrayOfStocks.push(cursor.value);
cursor.continue();
}
else{
console.log(arrayOfStocks);
console.log('done!');
deferred.resolve(arrayOfStocks);
return deferred.promise;
//return arrayOfStocks;
}
}
cursorRequest.onerror = function(){
console.log('could not fetch data');
}
},
deleteStock: function() {}
}
//return dataMethods;
if (window.indexedDB) {
console.log('indexeddb is supported');
var openRequest = indexedDB.open("users_stocks", 4);
openRequest.onupgradeneeded = function(e) {
var thisDB = e.target.result;
if (!thisDB.objectStoreNames.contains("portfolio")) {
console.log('created object store');
thisDB.createObjectStore("portfolio", {
autoIncrement: true
});
}
}
openRequest.onsuccess = function(e) {
console.log('connection opened');
dataMethods.db = e.target.result
}
openRequest.onerror = function(e) {
console.log('could not open connection');
}
return dataMethods;
}
else {
console.log('indexedDB not supported');
}
}]);
and then here is my controller code:
stocks.controller('portfolio', ['$scope', '$http', 'stockData', 'database', function portfolio($scope, $http, stockData, database) {
$scope.getAllStocks = function(){
console.log('running getll stocks');
database.readOnlyStock().then(function(result) {
console.log('done');
$scope.allstuff = result;
}, function(){
console.log('no');
});
}
}]);
not sure where the issue is.
You need to return the promise from the readOnluStock method, not from the success handler within it
readOnlyStock: function () {
var deferred = $q.defer();
var transaction = this.db.transaction(["portfolio"], "readonly");
var store = transaction.objectStore("portfolio");
// var cursorRequest = store.openCursor();
var arrayOfStocks = [];
var keyRange = IDBKeyRange.lowerBound(0);
var cursorRequest = store.openCursor(keyRange);
cursorRequest.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
arrayOfStocks.push(cursor.value);
cursor.
continue ();
} else {
console.log(arrayOfStocks);
console.log('done!');
deferred.resolve(arrayOfStocks);
//return arrayOfStocks;
}
}
cursorRequest.onerror = function () {
console.log('could not fetch data');
}
// the return should be here
return deferred.promise;
},
if(cursor){
arrayOfStocks.push(cursor.value);
cursor.continue();
}
when the control reaches this part, it doesnt return anything explicitly. It means that by default undefined will be returned by javascript. So, you are trying to call then on undefined. You might want to change this to
if(cursor){
arrayOfStocks.push(cursor.value);
cursor.continue();
return deferred.promise;
}

Uncaught TypeError: Cannot call method 'transaction' of undefined when using indexedDB

I have the following code for getting records from indexeddb on chrome 30.
var IndexedDBStorage = function (name) {
// until we won't need this prefix mess
var indexedDB = window.indexedDB || window.webkitIndexedDB
|| window.mozIndexedDB || window.msIndexedDB;
var IDBTransaction = window.IDBTransaction ||
window.webkitIDBTransaction;
var db;
// The initialization of our stuff
this.Supported = function () {
return indexedDB;
};
this.type = function () {
return "IndexedDB";
};
this.Setup = function () {
var dbVersion = 1.0;
var openRequest = indexedDB.open(name, dbVersion);
//handle setup - as the spec like it
openRequest.onupgradeneeded = function (e) {
console.log("running onupgradeneeded");
var thisDb = e.target.result;
if (!thisDb.objectStoreNames.contains(name)) {
var objectStore = thisDb.createObjectStore(name, {
autoIncrement: false
});
objectStore.createIndex("dataKey", "dataKey",
{ unique: false });
}
};
openRequest.onsuccess = function (e) {
db = e.target.result;
db.onerror = function (event) {
alert("Database error: " + event.target.errorCode);
console.dir(event.target);
};
if (db.setVersion) {
console.log("in old setVersion: " + db.setVersion);
if (db.version != dbVersion) {
var req = db.setVersion(dbVersion);
req.onsuccess = function () {
var ob = db.createObjectStore(name, {
autoIncrement: false
});
ob.createIndex("datakey",
"datakey", { unique: false });
var trans = req.result;
trans.oncomplete = function (ex) {
console.log("== trans oncomplete ==");
};
};
}
}
console.log(db);
};
};
this.GetAll = function (callback) {
console.log(db);
var transaction = db.transaction([name]); <-- gives error described below
var store = transaction.objectStore(name);
var items = [];
transaction.oncomplete = function (evt) {
callback(items);
};
var cursorRequest = store.openCursor();
cursorRequest.onerror = function (error) {
console.log(error);
};
cursorRequest.onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor) {
items.push({ key: cursor.key, body: cursor.value.body });
cursor.continue();
}
};
};
};
if i call it from a button like this :
it works fine if i do like this and call it from a button click, it works just fine:
function Init() { <-- called from script tag in index.html
$(document).ready(function () {
window.dataStore = new Store("data");
});
}
function getAll() { <-- button lick function
window.dataStore.getAll();
}
however, if i call it directly after initialization like this
function Init() {
$(document).ready(function () {
window.dataStore = new Store("data");
window.dataStore.GetAll();
});
}
i get a error with
Uncaught TypeError: Cannot call method 'transaction' of undefined
i am guessing it is because the db variable has not yet been globally set from openRequest.onsuccess when i call directly after init.
How can i fix this so it gets set properly
This is due the async behavior of the indexedDB API.
The db variable isn't assigned yet because the onsucces isn't called yet. To solve this you will have to provide a callback when the onsuccess is called on the openrequest, or you will have to delay the execution of the getAll call as long if the db variable is undefined.

Categories