I am doing a ajax call and store the response data into indexedDB. The response is an array of strings. After checking many questions and suggestions, i have followed the answer of #buley and did like this below :
$(document).ready(function () {
var db_name = 'mobileClaimsDb',
store_name = 'claims';
$.ajax({
url: 'index.cfm?action=main.appcache',
type: 'post',
cache:true,
success: function (data) {
var request,
upgrade = false,
doTx = function (db, entry) {
addData(db, entry, function () {
getData(db);
});
},
getData = function (db) {
db.transaction([store_name], "readonly").objectStore(store_name).openCursor(IDBKeyRange.lowerBound(0)).onsuccess = function (event) {
var cursor = event.target.result;
if (null !== cursor) {
console.log("entry", cursor.value);
cursor.continue();
}
};
},
addData = function (db, entry, finished) {
console.log('adding', entry);
var tx = db.transaction([store_name], "readwrite"),
claims = [];
tx.addEventListener('complete', function (e) {
finished();
});
$.each(claims, function (key, value) {
tx.objectStore(store_name).add(value);
});
};
request = window.indexedDB.open(db_name);
request.oncomplete = function (event) {
if (upgrade) {
doTx(request.result, data);
}
};
request.onsuccess = function (event) {
if (!upgrade) {
doTx(request.result, data);
}
};
request.onupgradeneeded = function (event) {
var db = event.target.result;
db.createObjectStore('claims', {
keyPath: null,
autoIncrement: true
});
}
}
});
});
It is creating the db and store too but data is not showing while opening the store.But, it is showing the data in console with key/value pair. I am not understand why it is not showing.
It is showing like this.
In console, it is populating properly.
What changes i need to do to show the key and value pair in store.
Related
In my application, I'm trying to use sendBeacon to send data to my remote server. One of the data that I need is how many clicks its been on the page and I'm doing it as follows:
var clickNumber = 0;
document.addEventListener("mouseup", function () {clickNumber++;});
var SendToRemote = window.SendToRemote || [];
SendToRemote.init({
clicks: clickNumber
});
My sendBeacon
navigator.sendBeacon = (url, data) =>
window.fetch(url, { method: 'POST', body: {data: data}, credentials: 'include' });
My only issue now is that the clickNumber is always 0 (which is the default value) and even that mouseup does increment clickNumber, but when sending it sends 0.
How am I able to update the clickNumber so when sendBeacon is triggered, it gets the incremented/updated clickNumber instead of 0.
This is my SendToRemote.init which works fine: (PS: I have removed parts of the codes as it would be over 1000 lines, but kept whats needed):
if (!SendToRemote) {
var SendToRemote = (function(){
var defaults = {
endpoints: {
unload: "https://remote.com"
},
processData: function(results){},
},
results = {
click: 0,
// more stuff here
},
support = !!document.querySelector && !!document.addEventListener,
settings;
var actions = {
sendData: function () {
results.hmn = parseInt(actions.hmnDetection(
results.times.tt, results.times.tp, results.click, results.mouse, results.touch, results.scroll, results.tab
));
let url = settings.endpoints.unload,
data = JSON.stringify(results);
navigator.sendBeacon(url, data);
},
// more functions here
}
function init(options) {
document.addEventListener('DOMContentLoaded', (event) => {
// More stuff here
// Event Listener to porcess
if(modifiable.processOnAction){
let node = document.querySelector(modifiable.selector);
if(!!!node) throw new Error('Selector was not found.');
actions._e(node, modifiable.event, `init-${modifiable.selector}-processOnAction`, function() {
let nodeInput = document.getElementsByName(modifiable.element)[0];
if(!!!nodeInput) throw new Error('nodeInput was not found.');
nodeInput.value = JSON.stringify(results);
hasProcessed = true;
})
}
addEventListener('unload', (event) => {
if (!navigator.sendBeacon) {
navigator.sendBeacon = (url, data) =>
window.fetch(url, { method: 'POST', body: {data: data}, credentials: 'include' });
}
if (!hasProcessed) {
actions.sendData();
hasProcessed = true;
}
return;
});
});
}
function processResults(){
if(settings.hasOwnProperty('processData')){
if (!modifiable.processOnAction){
return settings.processData.call(undefined, results);
}
return results;
}
return false;
}
// Module pattern, only expose necessary methods
return {
init: init,
processResults: processResults,
};
})();
}
Thanks in advance!
Im trying to create a chrome extension, and have encountered an annoying problem. I have this function, where I add an object to my indexedDB if the urlKeyValue of that object, does not already exist in the database.
If the urlKeyValue does exist in the DB, i want to get the object in the DB that contains that value. This is where my problem begins. On line 184 - 188, i try to get the object by searching by the `urlKeyValue, but when I try to print the object, i get undefined.
Question: How to get an object from IndexedDB by a value?
This is how my objects are structured:
{
message: "insert",
payload: [
{
urlKeyValue: "",
url: {
[userId]: {
[time]: {
msg: form_data.get("message"),
},
},
},
},
],
}
My Function where it all happens:
function insert_records(records, when) {
if (db) {
const insert_transaction = db.transaction(["roster2"], "readwrite");
const objectStore = insert_transaction.objectStore("roster2");
return new Promise((resolve, reject) => {
insert_transaction.oncomplete = function () {
console.log("ALL INSERT TRANSACTIONS COMPLETE.");
resolve(true);
};
insert_transaction.onerror = function () {
console.log("PROBLEM INSERTING RECORDS.");
resolve(false);
};
records.forEach((person) => {
// the "when" varieable isnt important, just disregard it
if (when != "init") {
const index = objectStore.index("urlKeyValue");
let search = index.get(person.urlKeyValue);
search.onsuccess = function (event) {
if (search.result === undefined) {
// no record with that key
let request = objectStore.add(person);
request.onsuccess = function () {
console.log("Added: ", person);
};
}
else {
const request2 = objectStore.get(person.urlKeyValue);
request2.onsuccess = function (event) {
console.log("--------" + event.target.result);
};
}
};
} else {
// this else statement isnt really important for this question
let request = objectStore.add(person);
request.onsuccess = function () {
console.log("Added: ", person);
//self.location.href;
};
}
});
});
}
}
EDIT:
This is an example of an object I store:
let roster = [
{
urlKeyValue: "https://www.youtube.com/",
"https://www.youtube.com/": {
1: {
20: {
msg: "this is some init data",
},
},
},
},
];
I'm trying to run parellel functions with async.js
But when I try to update rows of a database, the async function doesn't handle different inputs.
It updates the same values for the where part, which always updates only one record. How can I turn local variables for parallel runs of the same function different?
This is my code:
exports.run_mercadolibre_jobs = function() {
var Model = require('../../models/index').Model;
var async = require("async");
var values = {
attributes: ['environment_hash'],
raw: true
};
Model
.findAll(values)
.then(function(accounts) {
async.map(accounts, function (account) {
module.exports.refresh_access_token(account.environment_hash);
});
});
}
exports.refresh_access_token = function(environment_hash) {
...
var env_hash = environment_hash;
where = { environment_hash: env_hash };
Model.findOne({where: where}).then(function (account) {
if (!account) {
// Item not found, create a new one
} else {
// Found an item, update it
values = {
refresh_token: body.refresh_token,
expires_in: expires_in
};
Model.update(values, {where: where})
.then(function () {
console.log('updated!');
})
.catch(function (err) {
console.log('error on update');
});
}
});
}
});
}
I have the following model with a file reading function. However, the reading is done after the next piece of code. Why and how can I get it to return the read content of the file?
TreeContainer = Backbone.Model.extend({
elementCount: 0,
file: '',
object: {jj: "kk"},
type: "input",
parent: d3.select("#canvas"),
initialize: function () {
var result = this.readFile();
for (var i = 0; i < 200; i++) {
console.log(i); //this is resulted before the readFile content
}
},
readFile: function () {
var model = this;
// display text
if (this.get('file').name.endsWith(".json") || this.get('file').type === "application/json") {
var reader = new FileReader();
reader.onload = function (e) {
//parseJSON
var text = e.target.result;
var data = JSON.parse(text);
model.set('object', data);
console.log(data);
return data;
};
reader.readAsText(this.get('file'));
}
}
});
You have fallen for the async for loop problem
You can only loop over all files after you have read all the content
Here is a example using Screw-FileReader
initialize: function(){
this.readFile().then(arr => {
for (let json of arr) {
console.log(json) //this is resulted before the readFile content
}
})
},
readFile: function() {
function isJSON(file) {
return file.name.toLowerCase().endsWith('.json') ||
file.type === 'application/json'
}
return Promise.all(
Array.from(input.files)
.filter(isJSON)
.map(file => file.json())
)
}
Alternetive is to wrap FileReader in a Promise
return new Promise(resolve => {
reader.onload = function (e) {
var text = e.target.result
var data = JSON.parse(text)
model.set('object', data)
resolve(data)
}
})
or send in a callback
initialize: function(){
this.readFile(json => {
json
})
},
readFile: function(resolve) {
resolve(data)
}
I am trying to stub several ajax calls, but I want to have both beforeSend and success executed, is this possible?
I want something like this:
var stub = sinon.stub(jQuery, "ajax");
stub.onCall(0).yieldsTo("beforeSend").yieldsTo("success", {some: 'data'});
stub.onCall(1).yieldsTo("beforeSend").yieldsTo("success", {other: 'stuff'});
But this skips the 'beforeSend' method.
I know it would be easier to allow ajax to do it's stuff and use sinon's fakeServer, but I can't as I'm testing in Node with a fake browser and it just doesn't work
You could use yieldTo after the call:
var stub = sinon.stub();
stub({
foo: function() {
console.log('foo');
},
bar: function() {
console.log('bar');
}
});
stub.yieldTo('foo');
stub.yieldTo('bar');
I was able to work around this by adding some additional code:
var responses = {};
var executionComplete;
beforeEach(function () {
executionComplete = $.Deferred();
sinon.stub($, "ajax", function (options) {
if (options.beforeSend) {
options.beforeSend();
}
completeAjaxCall(options);
});
});
afterEach(function () {
$.ajax.restore();
});
var completeAjaxCall = function (options) {
var response = findResponse(options.url, options.type);
setTimeout(function () {
if (response.code < 400) {
if (options.dataFilter && response.data) {
response.data = options.dataFilter(JSON.stringify(response.data));
}
if (options.success) {
options.success(response.data);
}
} else {
if (options.error) {
options.error(response.data);
}
}
if (options.complete) {
options.complete();
}
if (response.completeExecution) {
executionComplete.resolve();
}
}, response.serverResponseTime);
};
var findResponse = function (url, type) {
var response = responses[url];
expect(response, url + ' should have a response').to.exist;
expect(response.type).to.equal(type);
delete responses[url];
if (Object.keys(responses).length === 0) {
response.completeExecution = true;
}
return response;
};
var givenResponse = function (response) {
responses[response.url] = response;
};
Then in my test I can use it like this:
it('should do some stuff', function (done) {
//given
givenResponse({serverResponseTime: 4, code: 200, url: '/saveStuff', type: 'POST'});
givenResponse({serverResponseTime: 1, code: 200, url: '/getStuff', type: 'GET'});
//when
$('button').click();
//then
executionComplete.then(function () {
expect(something).to.be.true;
done();
});
});