I'm trying to update an Object Store in IndexedDB from a Service Worker, this is my code right now:
function updateUrlLink(url_link) {
var request = indexedDB.open('db', 1);
var url_link_value = url_link;
request.onsuccess = function (event) {
var store = request.result.transaction("url_link", "readwrite").objectStore("url_link");
store.add(url_link_value, "url_link");
};
request.onupgradeneeded = function (event) {
var db = event.target.result;
var store = db.createObjectStore('url_link');
};
}
Is this the right way to update url_link or is there other way?
Related
I am using javascript to do this.
I want to add data to the database (indexedDB). The data will be coming from the webservice as json and I am looping through it and adding it to an objectStore with a keyPath.
When I look at the data from the webservice, I have an array of 186 objects but when I read the data from indexedDB, I have 151. When I went to check the database to see if the data was there, it wasn't... So something must be going on with my add function.
Here is my code:
Opening a database with an objectStore:
let db;
let request = window.indexedDB.open("WHS", 4);
request.onerror = function(event) {
console.log(event.target.errorCode);
};
request.onsuccess = function(event) {
db = event.target.result;
};
request.onupgradeneeded = function(event) {
let db = event.target.result;
let palletStore = db.createObjectStore("pallets", { keyPath: "palletno" });
};
Adding data after passing it to my function:
function addPalletsToIDB(pallets) {
let transaction = db.transaction(["pallets"], "readwrite");
let objectStore = transaction.objectStore("pallets");
$.each(pallets, function(i, pallet) {
let request = objectStore.put(pallet);
})
request.onsuccess = function(event) {
console.log('Added pallets : ', event.target.response);
};
transaction.oncomplete = function() {
getPalletDataFromIDB();
}
};
Reading the data:
function getPalletDataFromIDB() {
palletsFromIDB = [];
let transaction = db.transaction(["pallets"], IDBTransaction.READ);
transaction.oncomplete = function(event) {
console.log(event);
};
transaction.onerror = function(event) {
console.log(event.type);
};
let objectStore = transaction.objectStore("pallets");
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
palletsFromIDB.push(cursor.value);
cursor.continue();
}
transaction.oncomplete = function() {
console.log("[palletsFromIDB] ", palletsFromIDB);
toastr.info("Got pallets");
};
};
};
from web service : {pallets: Array(186)}
from indexedDB : [palletsFromIDB] (151)
One way to do this is to just create a unique keyPath in your json and making that your keyPath in indexed db.
I have created a function to store data in indexed db:
var request = window.indexedDB.open("mynewDB", 1);
request.onupgradeneeded = function(event) {
var db = event.target.result;
var objectStore = db.createObjectStore("toDoList", {keyPath: 'key', autoIncrement: true});
var txn = event.target.transaction;
var addRequest = txn.objectStore("toDoList").add({value: storagedata});
}
(FYI: the storagedata is filled with a base64 string)
If i am executing this function via button the content of variable storagedata is in the IndexedDB. But if i want to press the button again to store another value into the IndexedDB, nothing happens.
In addition to that if i am executing the function the second time the function jumps at line request.onupgradeneeded = function(event) { in to the timeout of file "intervalTrigger-dbg.js" to code clearTimeout(this._delayedCallId);
What i did to solve the problem: debugging in browser and reading a lot of documentations about indexeddb.
I fixed the problem on my own.
For everyone who want to know how it works:
var request = window.indexedDB.open("yourDB-1", 1);
var db;
var transaction;
var store;
request.onupgradeneeded = function(event) {
var db = event.target.result;
var transaction = event.target.transaction;
var store = db.createObjectStore("yourDB", {keyPath: 'key', autoIncrement: true});
}
request.onerror = function (event) {
console.log("Here is a error: " + event.target.errorCode);
}
request.onsuccess = function (event) {
db = request.result;
transaction = db.transaction("yourDB", "readwrite");
store = transaction.objectStore("yourDB");
db.onerror = function(event){
console.log("ERROR" + event.target.errorCode);
}
store.put({value: storagedata});
transaction.complete = function() {
db.close();
}
}
I have created a tracking and recommendation for customers, and it gets the data from the search engine. I'm using AJAX to get data of the products from MongoDB, and customers can also search for products that are stored in MongoDB. The problem is, I cannot display the products stored in MongoDB. There is no error in the console log, and when I search for products on the search engine, the recommendation works, but my products in MongoDB doesn't show up on my website.
HTML & AJAX
<input id="search_engine" type="text" name="search" placeholder="Search for accessories...">
<button id="search_item" onclick="loadContent()"></button>
<h2>Recommendations</h2>
<div id="RecomendationDiv"></div>
<script>
//Create recommender object - it loads its state from local storage
var recommender = new Recommender();
//Display recommendation
window.onload = showRecommendation;
//Searches for products in database
function loadContent() {
var search = document.getElementById("search_engine").value;
// Create request object
var request = new XMLHttpRequest();
// Create event handler that specifies what should happen when server responds
request.onload = function() {
// Check HTTP status code
if (request.status == 200) {
// Get data from server
var responseData = request.responseText;
// Add data to page
document.getElementById("product_grid").innerHTML = responseData;
} else
alert("Error communicating with server: " + request.status);
}
// Set up request with HTTP method and URL
request.open("POST", "php/search.php");
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// Send request
request.send("search=" + search);
//Add the search keyword to the recommender
recommender.addKeyword(search);
showRecommendation();
}
//Display the recommendation in the document
function showRecommendation() {
document.getElementById("RecomendationDiv").innerHTML =
recommender.getTopKeyword();
}
</script>
JavaScript
//Constructor for the recommender object
function Recommender() {
this.keywords = {}; //Holds the keywords
this.timeWindow = 10000; //Keywords older than this window will be deleted
this.load();
}
//Adds a keyword to the recommender
Recommender.prototype.addKeyword = function(word) {
//Increase count of keyword
if (this.keywords[word] === undefined)
this.keywords[word] = {
count: 1,
date: new Date().getTime()
};
else {
this.keywords[word].count++;
this.keywords[word].date = new Date().getTime();
}
console.log(JSON.stringify(this.keywords));
//Save state of recommender
this.save();
};
/* Returns the most popular keyword */
Recommender.prototype.getTopKeyword = function() {
//Clean up old keywords
this.deleteOldKeywords();
//Return word with highest count
var maxCount = 0;
var maxKeyword = "";
for (var word in this.keywords) {
if (this.keywords[word].count > maxCount) {
maxCount = this.keywords[word].count;
maxKeyword = word;
}
}
return maxKeyword;
};
/* Saves state of recommender. Currently this uses local storage,
but it could easily be changed to save on the server */
Recommender.prototype.save = function() {
localStorage.recommenderKeywords = JSON.stringify(this.keywords);
};
/* Loads state of recommender */
Recommender.prototype.load = function() {
if (localStorage.recommenderKeywords === undefined)
this.keywords = {};
else
this.keywords = JSON.parse(localStorage.recommenderKeywords);
//Clean up keywords by deleting old ones
this.deleteOldKeywords();
};
//Removes keywords that are older than the time window
Recommender.prototype.deleteOldKeywords = function() {
var currentTimeMillis = new Date().getTime();
for (var word in this.keywords) {
if (currentTimeMillis - this.keywords[word].date > this.timeWindow) {
delete this.keywords[word];
}
}
};
keith, have you tried testing it out with the rest of the code from the project first?
Now I'm trying to implement Unity Webgl with jslib. I'm so confused about how to call method in another method's function. I want to call method Recv when message was coming (ws.onmessage). But, it show "TypeError: this.Recv is undefined". Could you please help me figure out this source? Thank you !!!!!
Here's my source code
var ws = null;
var init_url = "";
var received_msg = "";
var error_msg = "";
var WebsocketLib = {
Hello: function(){
window.alert("Hello,world!");
},
InitSocket: function(url){
init_url = Pointer_stringify(url);
console.log("InitWebSocket: "+init_url);
ws = new WebSocket(init_url);
ws.onopen = function(evt){
console.log("Connect");
isConnected = false;
ws.send("hello");
};
ws.onclose = function(evt) {
console.log("Close");
isConnected = false;
};
ws.onmessage = function(evt) {
received_msg = evt.data;
console.log("[recv] "+received_msg);
this.Recv.call(this);
};
ws.onerror = function(evt) {
error_msg = evt.data;
console.log("[error] "+error_msg);
this.Error.call(this);
};
},
Recv: function(){
console.log("[recv] "+received_msg);
var buffer = _malloc(received_msg.length + 1);
writeStringToMemory(returnStr, buffer);
return buffer;
},
Error: function(){
console.log("[error] "+error_msg);
var buffer = _malloc(error_msg.length + 1);
writeStringToMemory(error_msg, buffer);
return buffer;
}
}
Inside of ws.onmessage this will refer to ws (as we're inside a method of ws) and not WebsocketLib.
However, inside Initsocket, where you define the handlers, this would correctly (in the sense that this is what you want) refer to the WebsocketLib object, so you can create a bound function to bind the outer this value to be used as this inside the event handler, like this:
ws.onmessage = function(evt) {
received_msg = evt.data;
console.log("[recv] "+received_msg);
this.Recv.call(this);
}.bind(this);
in JavaScript the value of this behaves differently than in other languages. Its value depends on how the function is called. You can read more about it in the Mozilla MDN page.
To solve your specific problem you can:
InitSocket: function(url){
var that = this; // [1]
init_url = Pointer_stringify(url);
console.log("InitWebSocket: "+init_url);
ws = new WebSocket(init_url);
ws.onopen = function(evt){
console.log("Connect");
isConnected = false;
ws.send("hello");
};
ws.onclose = function(evt) {
console.log("Close");
isConnected = false;
};
ws.onmessage = function(evt) {
received_msg = evt.data;
console.log("[recv] "+received_msg);
that.Recv.call(that); // [2]
};
ws.onerror = function(evt) {
error_msg = evt.data;
console.log("[error] "+error_msg);
that.Error.call(that); // [2]
};
},
In line 1 I bind the this variable to a custom variable that I decided to call that (but you can call it as you want). Then in line 2 I used that instead of this.
Inside the ws.onmessage function the value of this is not referring to the instance of WebsocketLib, so you need to use this "trick" and access the right this value using the one saved in the closure, inside the value of that.
I have an array as my keypath using indexedDB and it works fine with Chrome and Firefox, but when I try to add/put using IE it gives me a DataError.
var request = window.indexedDB.open("MyTestDatabase");
request.onsuccess = function(event) {
var database = event.target.result;
var transaction = database.transaction(["document"], "readwrite");
var objectStore = transaction.objectStore("document");
var request = objectStore.put({title: 'MyDoc', version: 0});
request.onsuccess = function() {
console.log('document added');
};
request.error = function(error) {
console.log(JSON.stringify(error));
};
transaction.oncomplete = function() {
console.log('transaction complete');
};
transaction.onerror = function(error) {
console.log(JSON.stringify(error));
};
};
request.onupgradeneeded = function(event) {
event.target.result.createObjectStore("document", {keyPath: ['title', 'version']});
};
Error Screenshot:
How can I keep my double keyPath and get it to work with IE?
The only way to get around this at the moment is to create a string out of the array and use it at the key as Kyaw mentioned.
request.onupgradeneeded = function(event) {
event.target.result.createObjectStore("document", {keyPath: ['id']});
};
The id in the example would now have to be a concatenated string containing the title and version. Some like: MyDoc_0. You'd still store the title and version fields though so you can easily access them without have to split the id string.