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;
}
}
Related
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);
});
I'm developing HTML5 apps.
When user uploads image from their mobile, the size was too large.
I want to compress the image as PNG like the pngcrush way.
Is there any good way to choice on the frontend (like a javascript library)?
Or is it possible to port the pngcrush library to javascript?
There are a few projects out there which seem to be based around the idea of using emscripten (a LLVM-to-JavaScript compiler) to actually compile the source code from pngcrush to working JavaScript for the browser.
JavaScript-Packer/PNGCrush.html - based on pngcrush-1.7.27
richardassar/pngcrush.js - based on pngcrush-1.7.27
pngcrush-crushed - based on pngcrush-1.7.58
The version for pngcrush-1.7.27 is currently the only one that doesn't seem to produce corrupted images for me. I put together an example which uses promises here: http://plnkr.co/edit/iLpbOjlYiacR04oGdXSI?p=preview
Here's a basic usage example:
var instance = new pngcrush();
instance.exec(inputFile, function (stdoutEvent) {
console.log(stdoutEvent.data.line);
}).then(function (doneEvent) {
var outputFile = new Blob([doneEvent.data.data], { type: 'image/png' });
// do something with the outputFile
});
Here are the contents of the pngcrush-class.js file from the above plunker for reference:
(function(exports) {
var noop = function () {};
function pngcrush () {
this.callbacks = {
'error': [],
'done': [],
'start': [],
'stdout': []
};
}
pngcrush.prototype.exec = function (file, notify) {
var self = this;
if (this.execPromise) {
return this.execPromise.catch(noop).then(function () {
return self.exec(file, notify);
});
}
if (file.type !== 'image/png') {
return Promise.reject(file);
}
var promise = this.execPromise = this.readAsArrayBuffer(file).then(function (event) {
var arrayBuffer = event.target.result;
return self.initWorker().then(function (worker) {
var done = new Promise(function (resolve, reject) {
var offDone, offError, offStdout;
offDone = self.once('done', function (event) {
offError();
offStdout();
resolve(event);
});
offError = self.once('error', function (event) {
offDone();
offStdout();
reject(event);
});
offStdout = self.on('stdout', function (event) {
if (typeof notify === 'function') {
notify.call(self, event);
}
});
worker.postMessage({
'type': 'file',
'data': new Uint8Array(arrayBuffer)
});
worker.postMessage({
'type': 'command',
'command': 'go'
});
});
done.catch(noop).then(function () {
worker.terminate();
});
return done;
});
});
promise.catch(noop).then(function () {
if (promise === self.execPromise) {
delete self.execPromise;
}
});
return promise;
};
pngcrush.prototype.initWorker = function () {
var self = this;
if (this.workerPromise) {
return this.workerPromise;
}
var promise = this.workerPromise = new Promise(function (resolve, reject) {
var worker = new Worker('worker.js');
worker.onerror = function (event) {
var callbacks = [];
reject(event);
Array.prototype.push.apply(callbacks, self.callbacks.error);
while (callbacks.length) {
callbacks.shift().call(self, event);
}
};
worker.onmessage = function (event) {
if (event.data.type === 'ready') {
worker.onmessage = function (event) {
var name = event.data.type;
if (typeof self.callbacks[name] !== 'undefined') {
var callbacks = [];
Array.prototype.push.apply(callbacks, self.callbacks[name]);
while (callbacks.length) {
callbacks.shift().call(self, event);
}
}
};
resolve(worker);
}
};
});
promise.catch(noop).then(function () {
if (promise === self.workerPromise) {
delete self.workerPromise;
}
});
return promise;
};
pngcrush.prototype.on = function (name, callback) {
var self = this;
if (typeof this.callbacks[name] !== 'undefined' && typeof callback === 'function') {
this.callbacks[name].push(callback);
var off = (function () {
var ran = false;
return function () {
if (ran === true) {
return;
}
ran = true;
var idx = self.callbacks[name].lastIndexOf(callback);
if (idx !== -1) {
self.callbacks[name].splice(idx - 1, 1);
}
};
})();
return off;
}
return noop;
};
pngcrush.prototype.once = function (name, callback) {
var off = this.on(name, function () {
off();
callback.apply(this, arguments);
});
return off;
};
pngcrush.prototype.readAsArrayBuffer = function (file) {
var fileReader = new FileReader();
return new Promise(function (resolve, reject) {
fileReader.onerror = reject;
fileReader.onload = resolve;
fileReader.readAsArrayBuffer(file);
});
};
pngcrush.prototype.readAsDataURL = function (file) {
var fileReader = new FileReader();
return new Promise(function (resolve, reject) {
fileReader.onerror = reject;
fileReader.onload = resolve;
fileReader.readAsDataURL(file);
});
};
exports.pngcrush = pngcrush;
})(this);
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!
}
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;
}
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.