Getting count of unsaved records in Indexeddb - javascript

I have some records saved in an Indexeddb, One of the fields in my db is "modifieddate". I want to get a count of all the records where modified date is not null.
I can count all records in my database like this:
var request = store.count();
I have tried something like this:
var myIndex = store.index('modifiedDate');
var cts = myIndex.count();
But that doesnt work. Any ideas ?

Getting a count of the index should work. Make sure that you do not set the modifiedDate for objects that were never modified. If the modifiedDate property is undefined, null, or does not exist in the object's set of properties, then the index will not include the object, leading to only objects with a defined modifiedDate property being included in the modifiedDate index, which leads to count returning the property number.
The second problem is how you are using the count function. IDBObjectStore.count and IDBIndex.count return an IDBRequest object, not a number. You have to get the count asynchronously. This can be done easily using a callback function.
var countRequest = myIndex.count();
countRequest.onsuccess = function(event) {
var theActualCountNumber = event.target.result;
// Alternatives to above statement, use whatever you like
// var theActualCountNumber = countRequest.result;
// var theActualCountNumber = this.result;
console.log('Number of objects with a modifiedDate property: ',
theActualCountNumber);
};
You cannot return 'theActualCountNumber' variable value from the callback function. It is only defined and accessible within the function. So, whatever code that wants to use the count value after you have obtained it must be located within the function itself. A simple trick to make the code cleaner and easier to use is the following:
function countModified(db, callback) {
var tx = db.transaction('mystore');
var store = tx.objectStore('mystore');
var index = store.index('modifiedDate');
var request = index.count();
request.onsuccess = function(event) {
var count = event.target.result;
callback(count);
};
}
// An example of how to call it
var openRequest = indexedDB.open('mydb', myversion);
openRequest.onsuccess = function(event) {
var db = event.target.result;
countModified(db, onGetCountModified);
};
function onGetCountModified(count) {
console.log('There are %s modified objects', count);
}

Related

localStorage .parse .stringify

I need help with pushing 2 data values into localStorage. I know a little about the stringify and parse methods but cant grasp how to implement them.The 2 data values are from "Scores" and "saveName"(a username that is put into an input box).
var Score = (answeredCorrect * 20) + (timeleft);
var saveName = document.querySelector("#saveName");
function Storage() {
localStorage.setItem("User", JSON.stringify(saveName.value));
localStorage.setItem("Scores", JSON.stringify(Score));
var GetStorage = localStorage.getItem("User");
var GetStorage2 = localStorage.getItem("Scores");
return {
first:console.log("GetStorage: "+ GetStorage + GetStorage2),
second:GetStorage,
third:GetStorage2,
};
};
var values = Storage();
var first = values.first;
var second = values.second;
var third = values.third;
As mentioned in the comments you need to parse it once retrieved from storage with JSON.parse, also naming Storage should be avoided.
Since your making a wrapper for localstorage, it could be done like this:
const Store = {
set: (key, value) => localStorage[key] = JSON.stringify(value),
get: key => JSON.parse(localStorage[key])
}
Then you can simply call it like the following, with a set and get methods:
//
Store.set('Score', Score)
Score = Store.get('Score')
//
Store.set('User', saveName.value)
saveName = Store.get('User')
Though you only need to get() on page load as you already have the value in Score/saveName etc.

How do I check for a JSON string value in a jS if statement?

I'm calling user data from Memberstack which allows data to be stored as metadata in JSON. I have the following code:
// Set Variables //
var initiated = "Y" <--- demonstration purposes only
var startDate = new Date();
var currentDate = new Date();
// End set variqables. //
// Check initiated state. //
MemberStack.onReady.then(async function(member) {
var metadata = await member.getMetaData()
if (metadata = initiated.includes("Y")) {
runTimer();
} else {
var sDobj = {
startDate: startDate,
}
var initY = {
initiated: "Y"
}
var sDobjjson = JSON.stringify(sDobj);
var initYjson = JSON.stringify(initY);
member.updateMetaData(sDobj, initY)
}
})
// End check initiated state. //
Most of this is working except for the initial if statement (if (metadata = initiated.includes("Y"))) which is currently linked to the variable var initiated = "Y". What I need to do is search the data I have returned under the metadata string response instead of the predefined initiated variable value.
Here is console which correctly returns metadata = {"initiated":"N"} from Memberstack:
Can anybody help me to get my if statement on line 28 if (metadata = initiated.includes("Y")) to read the string value on line 26 metadata = {"initiated":"N"} instead of the predefined variable var initiated = "Y"?
Change this to
if (metadata = initiated.includes("Y")) {
runTimer();
}
This
if (metadata.initiated === "Y") {
runTimer();
}
The issue is that you are assigning the result of the validation to metadata. Also the initiated variable will not be accessible at that line as it is not defined yet

A function in JavaScript that returns an array. I am able to print the items in the array when the function is called, but not each item in the array

I am trying to create a Movie object from a Json output I got from an API. After each movie object is created, I add them an array of movies. All of this is inside a function and it returns the array of movies. When the function is called, I was able to console log the movies; however, when trying to get a specific item using an index, it returns undefined. Am I missing something in the code? Any help is greatly appreciated. Thanks!
function Movie(title, description, director, producer) {
this.title = title;
this.description = description;
this.director = director;
this.producer = producer;
}
var connectedToAPI = false;
function retrieveMovies() {
var movies = [];
// Create a request variable and assign a new XMLHttpRequest object to it.
var request = new XMLHttpRequest();
// Open a new connection, using the GET request on the URL endpoint
request.open('GET', 'https://ghibliapi.herokuapp.com/films', true);
request.onload = function() {
// Begin accessing JSON data here
var data = JSON.parse(this.response);
if (request.status >= 200 && request.status < 400) {
var x = 0;
data.forEach(movie => {
// var title = movie.title;
// var description = movie.description;
// var director = movie.director;
// var producer = movie.producer;
var film = new Movie(movie.title, movie.description, movie.director, movie.producer);
movies[x] = film;
x++;
});
} else {
console.log('error');
}
}
request.send();
connectedToAPI = true;
return movies;
}
var films = retrieveMovies();
if (connectedToAPI == true) {
console.log(films);
console.log(films.length);
console.log("THIS IS MOVIE NUMBER 3: ");
console.log(films[1]);
}
The console prints out:
[] //->this contains the movies when expanded
0 //->the length is zero
THIS IS MOVIE NUMBER 3:
undefined //->retrieving specific item returns udefined
Your code is running BEFORE the request has come back. This is known as a "Race condition". What you want is to pass a callback to your function or promise.
Put an argument in retrieveMovies like so
function retrieveMovies(callback)
Then pass the value of movies into your callback as an arg:
callback(movies)
But do that right after your forEach completes. Your main function won't have a value immediately.
Finally, before you call your api declare a variable onFinished and set it to a function that logs your results:
var onFinished = function(films){
console.log(films);
console.log(films.length);
console.log("THIS IS MOVIE NUMBER 3: ");
console.log(films[1]);
}
retrieveMovies(onFinished);
Note that you don't set the value of retrieveMovies or check for api connection state if you use this technique.
Also, you will note that you do not need to scope your movies array so far away from your loop. Or even at all...
The better technique would be to just invoke the callback with Array.map to avoid more clutter.
Simply invoke like this (delete your forEach and var movies entirely):
callback(data.map(m=> new Movie(m.title, m.description, m.director, m.producer));
A slick one-liner :)
forEach is not modifying variable 'x'. It works on copies, producing undesirable effects in this case. Use a traditional for loop in cases when an index is to be accessed/used

firebase - javascript object returning undefined

I have a firebase set up. here is the structure:
I am having trouble getting the 'newNroomID' value (that is a6QVH, a7LTN etc..).
this value will be use to compare with the other variable value.
I know that in javascript, to access the value of the object it can be done like this:
var card = { king : 'spade', jack: 'diamond', queen: 'heart' }
card.jack = 'diamond'
but it seems different story when it comes with the firebase or surely enough i am missing something. Here is my code.
var pokerRoomsJoin = firebase.database().ref(); // this is how i set it up this block of code is for reading the data only
pokerRoomsJoin.on('value', function(data){
var rID = data.val();
var keys = Object.keys(rID);
var callSet = false;
for (var i = 0 ; i < keys.length; i++) {
var indexOfKeys = keys[i];
var roomMatching = rID[indexOfKeys];
var matchID = roomMatching.newNroomID; // this does not work alwaus give me undefined
console.log('this return :' + matchID + ' WHY!')
console.log(roomMatching)
if(matchID == 'ffe12'){ // 'ffe12' is actually a dynamic value from a paramiter
callSet = true;
}
}
})
and here is the result of the console log:
strangely i am able to access it like this
var matchID = roomMatching.newNroomID // it return a6QVH and a7LTN one at a time inside the loop
only if i set up the ref to :
var pokerRoomsJoin = firebase.database().ref('room-' + roomId);
I've tried searching but seems different from the structure i have . am I having bad data structure? Save me from this misery , thanks in advance!
Let us see the code inside for loop line by line,
1. var indexOfKeys = keys[i];
now indexOfKeys will hold the key room-id
2. var roomMatching = rID[indexOfKeys];
here roomMatching will hold the object
{ 'firebasePushId': { newDealerName: 'b',
...,
}
}
Now
3. var matchID = roomMatching.newNroomID;
This of-course will be undefined because roomMatching has only one
property , firebasePushId.
To access newNroomID , you have to do something like this,
matchID = roomMatching.firebasePushKey.newNroomID .
One way to get firebasePushKeys will be using Object.keys(roomMatching).

return from JS function

basic JS question, please go easy on me I'm a newb :)
I pass 2 variables to the findRelatedRecords function which queries other related tables and assembles an Array of Objects, called data. Since findRelatedRecords has so many inner functions, I'm having a hard time getting the data Array out of the function.
As it currently is, I call showWin inside findRelatedRecords, but I'd like to change it so that I can get data Array directly out of findRelatedRecords, and not jump to showWin
function findRelatedRecords(features,evtObj){
//first relationship query to find related branches
var selFeat = features
var featObjId = selFeat[0].attributes.OBJECTID_1
var relatedBranch = new esri.tasks.RelationshipQuery();
relatedBranch.outFields = ["*"];
relatedBranch.relationshipId = 1; //fac -to- Branch
relatedBranch.objectIds = [featObjId];
facSel.queryRelatedFeatures(relatedBranch, function(relatedBranches) {
var branchFound = false;
if(relatedBranches.hasOwnProperty(featObjId) == true){
branchFound = true;
var branchSet = relatedBranches[featObjId]
var cmdBranch = dojo.map(branchSet.features, function(feature){
return feature.attributes;
})
}
//regardless of whether a branch is found or not, we have to run the cmdMain relationship query
//the parent is still fac, no advantage of the parent being branch since cmcMain query has to be run regardless
//fac - branch - cmdMain - cmdSub <--sometimes
//fac - cmdMain - cmdSub <-- sometimes
//second relationship query to find related cmdMains
var relatedQuery = new esri.tasks.RelationshipQuery();
relatedQuery.outFields = ["*"];
relatedQuery.relationshipId = 0; //fac -to- cmdMain
relatedQuery.objectIds = [featObjId];
//rather then listen for "OnSelectionComplete" we are using the queryRelatedFeatures callback function
facSel.queryRelatedFeatures(relatedQuery, function(relatedRecords) {
var data = []
//if any cmdMain records were found, relatedRecords object will have a property = to the OBJECTID of the clicked feature
//i.e. if cmdMain records are found, true will be returned; and continue with finding cmdSub records
if(relatedRecords.hasOwnProperty(featObjId) == true){
var fset = relatedRecords[featObjId]
var cmdMain = dojo.map(fset.features, function(feature) {
return feature.attributes;
})
//we need to fill an array with the objectids of the returned cmdMain records
//the length of this list == total number of mainCmd records returned for the clicked facility
objs = []
for (var k in cmdMain){
var o = cmdMain[k];
objs.push(o.OBJECTID)
}
//third relationship query to find records related to cmdMain (cmdSub)
var subQuery = new esri.tasks.RelationshipQuery();
subQuery.outFields = ["*"];
subQuery.relationshipId = 2;
subQuery.objectIds = [objs]
subTbl.queryRelatedFeatures(subQuery, function (subRecords){
//subRecords is an object where each property is the objectid of a cmdMain record
//if a cmdRecord objectid is present in subRecords property, cmdMain has sub records
//we no longer need these objectids, so we'll remove them and put the array into cmdsub
var cmdSub = []
for (id in subRecords){
dojo.forEach(subRecords[id].features, function(rec){
cmdSub.push(rec.attributes)
})
}
var j = cmdSub.length;
var p;
var sub_key;
var obj;
if (branchFound == true){
var p1 = "branch";
obj1 = {};
obj1[p1] = [cmdBranch[0].Branches]
data.push(obj1)
}
for (var i=0, iLen = cmdMain.length; i<iLen; i++) {
p = cmdMain[i].ASGMT_Name
obj = {};
obj[p] = [];
sub_key = cmdMain[i].sub_key;
for (var j=0, jLen=cmdSub.length; j<jLen; j++) {
if (cmdSub[j].sub_key == sub_key) {
obj[p].push(cmdSub[j].Long_Name);
}
}
data.push(obj);
}
showWin(data,evtObj) <---this would go away
})
}
//no returned cmdRecords; cmdData not available
else{
p = "No Data Available"
obj = {}
obj[p] = []
data.push(obj)
}
showWin(data,evtObj) <--this would go away
})
})
}
I'd like to have access to data array simply by calling
function findRelatedRecords(feature,evt){
//code pasted above
}
function newfunct(){
var newData = findRelatedRecords(feature,evt)
console.log(newData)
}
is this possible?
thanks!
Edit
Little more explanation.....
I'm connecting an Object event Listener to a Function like so:
function b (input){
dojo.connect(obj, "onQueryRelatedFeaturesComplete", getData);
obj.queryRelatedFeatures(input);
console.log(arr) //<----this doesn't work
}
function getData(relatedFeatData){
var arr = [];
//populate arr
return arr;
}
So when obj.QueryRelatedFeatures() is complete, getData fires; this part works fine, but how to I access arr from function b ?
Post Edit Update:
Due to the way that this event is being hooked up you can't simple return data from it. Returning will just let Dojo call to the next method that is hooked up to onSelectionComplete.
When init runs it is long before findRelatedRecords will ever be executed/fired by the onSelectionComplete event of the well, which is why you were seeing undefined/null values. The only way to work with this sort of system is to either 1) call off to a method like you're already doing or 2) fire off a custom event/message (technically it's still just calling off to a method).
If you want to make this method easier to work with you should refactor/extract snippets of it to make it a smaller function but contained in many functions. Also, changing it to have only one exit point at the end of the findRelatedRecords method will help. The function defined inside of subTbl.queryRelatedFeatures() would be a great place to start.
Sorry, you're kind of limited by what Dojo gives you in this case.
Pre Edit Answer:
Just return your data out of it. Everywhere where there is a showWin call just use this return.
return {
data: data,
evtObj: evtObj
}
Then your newfunct would look like this.
function newfunct(){
var newData = findRelatedRecords(feature,evt);
console.log(newData);
console.log(newData.data);
console.log(newData.evtObj);
}
If you only need that "data" object, then change your return to just return data;.
Also, start using semicolons to terminate statements.

Categories

Resources