Dexie.js delete one item with id not working - javascript

Hi this my simple project js code example
const deleteOneNote = (id) => {
const db = openNoteDb();
db.notes.where('id').equals(id).delete();
}
$(document).on("click", ".remove_note", function () {
const id = $(this).parent().parent().attr("id");
const db = openNoteDb();
db.notes.where('id').above(-1).modify(result => {
if (result.id == id) {
deleteOneNote(result.id);
window.location.reload(true)
}
})
})
But my delete function not working I am dont understand Please help me..

First of all, your function deleteOneNote() must return the promise from db.transaction() so you can wait for the delete to complete. Alternatively make the function async and await the promise returned by db.transaction(). Whatever you choose, the caller of your function must also await your function before testing if the delete was successful or not.
Then, I also see a common problem on the code, which is that the Dexie instance is created on-demand, which would lead to memory leak unless you close it when done. Instead, declare db on top-level so it will live throwout your entire application life time and let you functions use that same db instance everywhere.
A third common mistake (which might not be this cause though) is that people supply a string when the key was stored as a number, or vice versa. Make sure that the id supplied to your function is off the same type as in the object you want to delete.
// Declare one single Dexie instance in your entire application
// and use it from all functions.
const db = new Dexie("NotesDB");
// If you use modules, keep this code in a module and
// add an 'export' before 'const db = new Dexie("NotesDB");
db.version(1).stores({
notes: `
id,
time,
note,
noteBackColor,
noteTextColor,
projectType,
alarm`,
});
// Let you functions use the singleton Dexie instance:
const deleteOneNote = (id) => {
return db.transaction('rw', db.notes, function () {
// Note: Doing this in a transaction is over-kill, but ok.
return db.notes.delete(id);
}).catch((err) => {
console.log(err);
throw err; // Also, you probably want to rethrow the error...
});
}
Now, these are code recommendations from Dexie's best-practices section and not nescessarily reason for why your code fails to delete an item.
A more interesting thing is:
What's the value of the "id" property in your database of the object that you want to delete? I assume your object looks something like{id: "x", time: "y", ...}.
What argument do you pass to your function? If the object you are deleting looks like described in previous bullet, the value of the id argument must be exactly the string "x" - not the object and not an array or any other type - a string with the exact value "x".
A working test for this code would be:
const foo = {id: "x", time: "y"};
db.notes.put(foo).then(async () => {
if (await db.notes.get("x")) {
console.log("My object is there!");
} else {
console.log("My object is not there!");
}
console.log("Now deleting it...");
await deleteOneNote("x");
if (await db.notes.get("x")) {
console.log("My object is there!");
} else {
console.log("My object is not there!");
}
}).catch(console.error);
The result from running this test should be:
My object is there!
Now deleting it...
My object is not there!

Related

Why does this getter method has been called several times in React?

I have a Store which will be provided to the component. In this Store file, there are several getter function. But I find only this getter function will be executed three times since this.rawMonthlyImpacts will be only changed once when the api get response from backend. I am so confused because other getter function in this file will be only executed once. During every execution, this.rawMonthlyImpacts is always same. Because this function is time-consuming, so I want to figure out why this happens. Hope you can give me some advice. Thanks!
get Impacts(){
const monthlyImpacts = new Map<string, Map<string, number>>();
if (this.rawMonthlyImpacts) {
this.rawMonthlyImpacts.forEach((impact) => {
if (impact.Impact > 0) {
const month = TimeConversion.fromTimestampToMonthString(impact.Month);
const tenantId = impact.TenantId;
const tenantImpact = impact.Impact;
if (!monthlyImpacts.has(month)) {
const tenantList = new Map<string, number>();
monthlyImpacts.set(month, tenantList.set(tenantId, tenantImpact));
} else {
const tenantWithImpactMap = monthlyImpacts.get(month);
if (!tenantWithImpactMap.has(tenantId)) {
tenantWithImpactMap.set(tenantId, tenantImpact);
} else {
tenantWithImpactMap.set(tenantId, tenantWithImpactMap.get(tenantId) + tenantImpact);
}
monthlyImpacts.set(month, tenantWithImpactMap);
}
}
});
}
return monthlyImpacts;
},
Update: I have find that there are other two functions use this.Impacts. If I remove these two functions, the getter function will only be executed only once. I think the getter function uses the cache to store data, so once the data is calculated for the first time, subsequent calls to the getter function should not be re-executed, only the value in the cache needs to be retrieved. So I am very confused about why this getter function will be executed 3 times.
getImpactedTenants(month: string): string[] {
return Array.from(this.Impacts.get(month).keys());
},
get overallMonthlyImpactedTenants(): Map<string, number> {
return new Map<string, number>(
Array.from(this.Impacts)?.map((monthEntries) => {
const month = monthEntries[0];
const impactedTenants = monthEntries[1].size;
return [month, impactedTenants];
})
);
}
Hard to tell what exactly is happening without more context, but remember that with a get function, every single time you reference that property (.Impacts in this case) the get function will be called.
Assuming that each impact stored in this.rawMonthlyImpacts which you loop through is an instance of the class with this getter, then as far as I'm aware, you are calling the get function each time you reference impact.Impacts, such as in the conditional:
if (impact.Impact > 0) {
I might be way off though; I'm unfamiliar with React and so my answer is based only on my experience with vanilla JS.

How to get returned values from my listener's callback ES6 way

I made an input that let me filter a table of softwares.
<input type="text" id="softwares-search" class="form-control" aria-label="Input de recherche" aria-describedby="softwares-search">
Then in javascript my filter work well if I console.log(....)
But when I replace it with a return, nothing is returned. I think it is due to my var affectation through the event listener :
const maxwell = () => {
search = document.querySelector('#softwares-search').value;
return softwares.filter(row => row.name.includes(search) || row.description.includes(search));
}
const softwaresSearch = document.querySelector('#softwares-search');
if (softwaresSearch) {
var results = softwaresSearch.addEventListener('keyup', maxwell)
console.log(results);
}
Thank all
EDIT 1 :
I was so angry, so blind, I had S#!t in my eyes, no need to use a global :(
const softwaresSearch = document.getElementById('softwares-search');
if (softwaresSearch) {
softwaresSearch.addEventListener('keyup', (e) => {
search = document.getElementById('softwares-search').value;
var filtredSoftwares = softwares.filter(e => e.name.includes(search) || e.description.includes(search) );
renderTable(filtredSoftwares);
});
}
const renderTable = (softwares) => {
Object.values(softwares).forEach(value=>{
console.log(value);
});
// Todo build HTML table
}
Instead of returning I think you just need to replace the current array like this
const maxwell = () => {
search = document.querySelector('#softwares-search').value;
softwares = softwares.filter(row => row.name.includes(search) || row.description.includes(search));
}
And results is not needed:
const softwaresSearch = document.querySelector('#softwares-search');
if (softwaresSearch) {
softwaresSearch.addEventListener('keyup', maxwell)
}
As far as I know, softwareSearch.addEventListener won't return anything, since that is an event listener, and does not return any value. It simply executes the function passed in the 2nd parameter. You could try doing this instead
softwaresSearch.addEventListener('keyup', () => {
var results = maxwell();
console.log(results);
});
What this would do is that, it would call your maxwell function when the keyup event, since that is what it looks you are trying to do.
Please share all relevant code before posting a question, this code includes the variable "softwares" that exist outside what is visible to us.
Additionally, there are some issues with your code.
I don't understand your naming of the maxwell function. You should name functions as verbs, not anything else. A function is a machine that is doing something, and possibly returning something. It should be named to what it is doing.
On the second line, you say "search = ... ", but you didn't declare it as a variable.
You are returning something based on a value that isn't validated ('search' can be either undefined or a string value in this case), hence, your return will most likely just return undefined and not any value at all.
Your function can possibly not return anything at all since you are returning something within your if-statement. You can use a closure to always return something.
I would also suggest passing a search string as a variable to your function that should return a list based on the search query. Getting in the habit of short, concise functions with expected inputs/outputs, will make your code more readable and less error-prone and less likely to produce unwanted side-effects.
I don't know the rest of your code, but I don't recommend assigning variables in the global scope. Your "maxwell", "softwareSearch" variables both exist in the global space, unless you have wrapped them in another function block already (such as jquerys $(document).ready(() => { ...everything here is scoped })
You are getting the same element in two different places in your code.
Here is an updated code sample, but I can't test it since I don't know the rest of your code.
/*
* Executing the whole thing in this IIFE will make all variables declared inside here scoped to this block only,
* thus they can't interfere with other code you may write
*/
(() => {
const listOfSoftwares = softwares; // --- get your softwares variable here somehow, I don't know where "software" comes from.
// input element
const search = document.querySelector('#softwares-search');
/**
* Filter search results
* #param {string} query Search query
* #returns {Array} The results array
*/
const filterSoftwareSearchResults = (query) => {
let results = [];
results = listOfSoftwares.filter(software => software.description.includes(query) || software.title.includes(query))
// Verify
console.log(results);
// Should return array of results, even if empty
return results;
}
if (search) {
search.addEventListener('keyup', () => {
filterSoftwareSearchResults(search.value)
})
}
})()
The addEventListener function always returns undefined, so your results variable is undefined.
Returning from the callback function (maxwell) is also of no use.
You either need to do something with the data inside of your callback, or maybe pass the data to a global variable.

How to include or detect the name of a new Object when it's created from a Constructor

I have a constructor that include a debug/log code and also a self destruct method
I tried to find info on internet about how to detect the new objects names in the process of creation, but the only recommendation that I found was pass the name as a property.
for example
var counter = {}
counter.a =new TimerFlex({debug: true, timerId:'counter.a'});
I found unnecessary to pass counter.a as a timerId:'counter.a' there should be a native way to detect the name from the Constructor or from the new object instance.
I am looking for something like ObjectProperties('name') that returns counter.a so I don't need to include it manually as a property.
Adding more info
#CertainPerformance What I need is to differentiate different objects running in parallel or nested, so I can see in the console.
counter.a data...
counter.b data...
counter.a data...
counter.c data... etc
also these objects have only a unique name, no reference as counter.a = counter.c
Another feature or TimerFlex is a method to self desruct
this.purgeCount = function(manualId) {
if (!this.timerId && manualId) {
this.timerId = manualId;
this.txtId = manualId;
}
if (this.timerId) {
clearTimeout(this.t);
this.timer_is_on = 0;
setTimeout ( ()=> { console.log(this.txtId + " Destructed" ) },500);
setTimeout ( this.timerId +".__proto__ = null", 1000);
setTimeout ( this.timerId +" = null",1100);
setTimeout ( "delete " + this.timerId, 1200);
} else {
if (this.debug) console.log("timerId is undefined, unable to purge automatically");
}
}
While I don't have a demo yet of this Constructor this is related to my previous question How to have the same Javascript Self Invoking Function Pattern running more that one time in paralel without overwriting values?
Objects don't have names - but constructors!
Javascript objects are memory references when accessed via a variables. The object is created in the memory and any number of variables can point to that address.
Look at the following example
var anObjectReference = new Object();
anObjectReference.name = 'My Object'
var anotherReference = anObjectReference;
console.log(anotherReference.name); //Expected output "My Object"
In this above scenario, it is illogical for the object to return anObjectReference or anotherReference when called the hypothetical method which would return the variable name.
Which one.... really?
In this context, if you want to condition the method execution based on the variable which accesses the object, have an argument passed to indicate the variable (or the scenario) to a method you call.
In JavaScript, you can access an object instance's properties through the same notation as a dictionary. For example: counter['a'].
If your intent is to use counter.a within your new TimerFlex instance, why not just pass counter?
counter.a = new TimerFlex({debug: true, timerId: counter});
// Somewhere within the logic of TimerFlex...
// var a = counter.a;
This is definitely possible but is a bit ugly for obvious reasons. Needless to say, you must try to avoid such code.
However, I think this can have some application in debugging. My solution makes use of the ability to get the line number for a code using Error object and then reading the source file to get the identifier.
let fs = require('fs');
class Foo {
constructor(bar, lineAndFile) {
this.bar = bar;
this.lineAndFile = lineAndFile;
}
toString() {
return `${this.bar} ${this.lineAndFile}`
}
}
let foo = new Foo(5, getLineAndFile());
console.log(foo.toString()); // 5 /Users/XXX/XXX/temp.js:11:22
readIdentifierFromFile(foo.lineAndFile); // let foo
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
function getLineAndFile() {
let err = getErrorObject();
let callerLine = err.stack.split("\n")[4];
let index = callerLine.indexOf("(");
return callerLine.slice(index+1, callerLine.length-1);
}
function readIdentifierFromFile(lineAndFile) {
let file = lineAndFile.split(':')[0];
let line = lineAndFile.split(':')[1];
fs.readFile(file, 'utf-8', (err, data) => {
if (err) throw err;
console.log(data.split('\n')[parseInt(line)-1].split('=')[0].trim());
})
}
If you want to store the variable name with the Object reference, you can read the file synchronously once and then parse it to get the identifier from the required line number whenever required.

Break down a code segment that uses some ES5 / advanced JavaScript methods of writing?

Can someone explain the part in the exports section, I seem to lost and stuck for a while. Starting from importPromise. It seems like there's a lot going on, such as arrow functions and map method. I can't see where the data flows from where to where.
const keystone = require('keystone');
const PostCategory = keystone.list('PostCategory');
const Post = keystone.list('Post');
const importData = [
{ name: 'A draft post', category: 'Keystone JS' },
...
];
exports = function (done) {
const importPromise = importData.map(({ name, category }) => createPost({ name, category }));
importPromise.then(() => done()).catch(done);
};
const categories = {};
const createPost = ({ name, category }) => {
let postCategory = new PostCategory.model({ category });
if (categories[category]) {
postCategory = categories[category];
}
categories[category] = postCategory;
const post = new Post.model({ name });
post.category = postCategory._id.toString();
return Promise.all([
post.save(),
postCategory.save()
]);
}
Quite some ES6 magic involved :)
const importPromise = importData.map(({ name, category }) => createPost({ name, category }));
importdata is an array. What the map function on an array does is to take every item of the array and apply a function to it, then return a new array with all of the items in the original array, but modified. map function
Instead of writing .map(function(item) { ... } the preferred way of writing this in ES6 is with a fat arrow function, i.e. .map((item) => ...
The third bit of magic is called destructuring assignment. What it does is it takes an object in this case, and assigns the obj.name and obj.category to two new variables name and category. We can use those variables within our function as if we had called the function with two separate arguments.
Now remember our map function dictates we write a function that takes an array item as a parameter, and returns the modified item. So what we end up with is a map function looping through the arguments of importData, taking name and category of each item and calling another function createPost with them. The result of createPost is the new value of the item, and it all gets appended to an array of the same size as the old one, with the modified items.
importPromise.then(() => done()).catch(done);
createPost creates a promise out of each item. You can read more about Promise here. The .then method on a Promise takes functions as its argument; to be called when the promise returns (either with success or an error). The () => done() is simply a function in fat arrow syntax that takes no arguments and calls the done function. .catch takes a function as well (done is a function), and is executed when the promise returns an error. NB. this way the done function is called both on success and on error!
--and no, this code won't work because what we're creating on the first line with importPromise is not actually a promise, but an array of promises!
Good luck with reading up, and as Beri suggests it might be worthwhile translating the code to es5 to follow along.
I don't know much about KeystoneJS. Anyway, here are my two cents:
const importData = [
{ name: 'A draft post', category: 'Keystone JS' },
// ...
];
importData is an Array which holds a bunch of Object instances, each having a name and category key with String values. For me, it appears this is some "mock data", which is simply put there for testing purposes.
I shifted the next parts, because it makes the code more understandable.
This part:
const categories = {};
Looks to me like the person who wrote it tried to implement some form of "caching". The categories constant is a mere "container" to store posts in so they can be reused later instead of being recreated. The createPost function reveals the purpose of it if you read through it.
const createPost = ({ name, category }) => {
let postCategory = new PostCategory.model({ category });
if (categories[category]) {
postCategory = categories[category];
}
categories[category] = postCategory;
const post = new Post.model({ name });
post.category = postCategory._id.toString();
return Promise.all([
post.save(),
postCategory.save()
]);
}
The first if seems to be there to make use of the "caching" construct (const category), but the way it does it is a bit confusing. Here's how I'd refactor it:
const createPost = ({ name, category }) => {
if (!categories[category]) {
categories[category] = new PostCategory.model({ category });;
}
const post = new Post.model({ name });
post.category = categories[category]._id.toString();
return Promise.all([
post.save(),
categories[category].save()
]);
}
Finally for the exports part:
The module exports a function which awaits a callback as argument (done). It then tries to create a Promise from all the "posts" of the mock data (and - to my understanding - fails), by mapping the createPost function over it. The reason I think it fails is because Array.prototype.map doesn't return a Promise, it returns a new Array instance which doesn't have a then method (see next line). Instead of calling then, it should be a Promise.all again. When that final Promise succeeds (or fails), the callback is called with the result.
exports = function (done) {
const importPromise = importData.map(({ name, category }) => createPost({ name, category }));
importPromise.then(() => done()).catch(done);
};
Again, I'd rewrite it this way:
exports = function (done) {
Promise.all(importData.map(createPost)).then(done).catch(done);
};
Or just return the final Promise and get rid of the done callback altogether.
https://babeljs.io/repl
You can use this tool to translate.

Passed-in Values Not Available at Run-time of Function in Angular App

I realize there is something I'm missing in terms of how and specifically when the products of certain functions are available in JavaScript.
In my Angular app, in order to get a user's initials, I am parsing data being returned from the API, and retrieving the first letter of the firstName, as well as the first letter of lastName in two different functions. These two functions are working as expected, and I can see the correct results in the console:
getFirstNameFirstLetter() {
if (this.authenticationService.isAuthenticated()) {
const userObj = JSON.parse(sessionStorage.getItem('currentUser'));
const userInfo = userObj.data;
const firstName = userInfo.name.first;
const firstNameFirstLetter = firstName.trim().charAt(0);
console.log(firstNameFirstLetter);
return firstNameFirstLetter;
}
}
getLastNameFirstLetter() {
if (this.authenticationService.isAuthenticated()) {
const userObj = JSON.parse(sessionStorage.getItem('currentUser'));
const userInfo = userObj.data;
const lastName = userInfo.name.last;
const lastNameFirstLetter = lastName.trim().charAt(0);
console.log(lastNameFirstLetter);
return lastNameFirstLetter;
}
}
Now comes the part I'm not fully understanding. When I then pass the returned values of these two functions, in order to get the initials, like this:
getInitials(firstNameFirstLetter, lastNameFirstLetter) {
if (this.authenticationService.isAuthenticated()) {
if (!this.firstNameFirstLetter || !this.lastNameFirstLetter) {
console.log('Names not ready!');
return;
} else if (this.firstNameFirstLetter && this.lastNameFirstLetter) {
console.log(firstNameFirstLetter + lastNameFirstLetter);
return firstNameFirstLetter + lastNameFirstLetter;
}
}
}
... I get "Names not ready!" printed to the console each time.
By the way, I am running these functions within Angular's ngOnInit life cycle hook, like this:
ngOnInit() {
this.getFirstNameFirstLetter();
this.getLastNameFirstLetter();
this.getInitials(this.firstNameFirstLetter, this.lastNameFirstLetter);
}
I know this has something to do with what's available when, because I get 'undefined' when I use break points and debug the two values being passed into the "getInitials()" function. In other words, the function doesn't have access to the returned values of the other two functions at the time it's run -- hence I'm getting 'Names not ready!' printed to the console. My question is, what am I missing, architecturally, to resolve this kind of issue?
So what is happening here is that JavaScript doesn't think you are using the return values for getFirstNameFirstLetter and getLastNameFirstLetter, so when it makes the call, instead of waiting for that call to finish, it goes on to the next one, which introduces a race condition. if you simply change it to
ngOnInit() {
let temp1 = this.getFirstNameFirstLetter();
let temp2 = this.getLastNameFirstLetter();
this.getInitials(this.firstNameFirstLetter, this.lastNameFirstLetter);
}
then it will wait for the previous functions to finish before calling the next.
Also, I don't use const very often, so I could be wrong and it could follow different scope rules, but by normal scope rules, setting a variable in that function, it is only available in that function, you would need to set it as
this.firstNameFirstLetter = firstName.trim().charAt(0);
to have access to it outside the function.
Or, so as to kill two birds with one stone, you could do
ngOnInit() {
this.firstNameFirstLetter = this.getFirstNameFirstLetter();
this.lastNameFirstLetter = this.getLastNameFirstLetter();
this.getInitials(this.firstNameFirstLetter, this.lastNameFirstLetter);
}
or
ngOnInit() {
let firstNameFirstLetter = this.getFirstNameFirstLetter();
let lastNameFirstLetter = this.getLastNameFirstLetter();
this.getInitials(firstNameFirstLetter, lastNameFirstLetter);
}
depending on if you need the variables again or just for that function.

Categories

Resources