I have a function for looking item exists or not.
addNewPerson(name) {
AsyncStorage.getItem('savedPersons', (err, result) => {
const name = [name];
if (result !== null) {
var newIds = JSON.parse(result).concat(name);
AsyncStorage.setItem('savedPersons', JSON.stringify(newIds));
console.log('Data Found', result);
} else {
AsyncStorage.setItem('savedPersons', JSON.stringify(name));
console.log('Data Added', name);
}
});
}
Now I want to delete some specific person in "savedPersons".
I Tried this code:
AsyncStorage.removeItem('savedPersons','Uzuner');
error text is : "callback is not a function."
How can I delete item in asycnStorage's array?
Solved:
I write this code for deleting item.
removePost = async (post_id) => {
try {
const posts = await AsyncStorage.getItem('savedPersons');
let postsFav = JSON.parse(posts);
const postsItems = postsFav.filter(function(e){ return e !== post_id });
// updating 'posts' with the updated 'postsItems'
await AsyncStorage.setItem('savedPersons', JSON.stringify(postsItems));
} catch(error) {
console.log('error: ', error);
}};
Thanks alot all users for replies.
AsyncStorage.removeItem is an asynchronous task which returns a promise or callback. Also, if you want to remove an element from the array then you need to get the array first,delete the element and push it back to the local storage. Something like this,
AsyncStorage.getItem("savedPersons")
.then(persons =>{
const index = persons.indexOf("Uzuner");
const modifiedPersons = persons.splice(index,1);
AsyncStorage.setItem("savedPersons",modifiedPersons)
.then(() => console.log(done))
.catch((error) => console.log("error"));
})
.catch(error => console.log("Error while retrieving the savePersons"));
Related
I'm trying to retrieve the _id field with Wix Velo of my logged in user. The code is working, however the function I'm using is returning [object Promise] instead of the id string that I need.
import wixData from 'wix-data';
export function getID() {
return wixData.query("Picks") // My Collection
.eq("player", "Gary") // A field, and a cell
.find()
.then((results) => {
if (results.items.length > 0) {
let firstItem = results.items[0]._id;
console.log("Return ID: " + firstItem) // This returns the ID I need
$w("#text31").text = firstItem;
// return firstItem.toString();
} else {
console.log("No Items Found")
}
})
.catch((err) => {
let errorMsg = err;
});
}
console.log("Return the ID outside of the function: " + getID()) // This returns "[object Promise]"
I've tried to use await, but it just gives me errors.
Since top-level-await is not supported by all the browsers, I believe Wix didn't open that feature as well. Instead, wrap it with an async IIFE.
(async () => {
console.log("Return the ID outside of the function: " + await getID())
})();
This answer has more details about top-level-await
Just incase this helps someone else, the answer was in nested promises. I had to call the first function getLoggedInUserName() to get the user name, and then pass that to a nested function called getID().
Essentially, this was a scope issue, and also waiting for the promise to be resolved.
getLoggedInUserName().then((results) => {
let userName = results;
getID(userName).then((results) => {
let userID = results;
let pick = $w("#dropdown1").value;
let toUpdate = {
"_id": userID,
"pick": pick,
"player": userName,
}
wixData.update("Picks", toUpdate)
.then((results) => {
$w("#text33").show();
let item = results;
})
.catch((err) => {
let errorMsg = err;
console.log("Error: " + errorMsg)
});
})
})
.catch((err) => {
let errorMsg = err;
});
I'm making an app and trying to get product data by it's id inside a modal in ionic 4.
I'm using typescript to do it but without luck.
Because de calls to firebase are asynchronous i cannot get the data that is held in firebase and also because i'm new to subject i cannot figured out the proper way to write the code.
I read about how to do it but i'm having a hard time to achieve it.
Here is my function that tries to grab product data from firebase.
It always logs empty on console.log('todo', todo).
async editProduct(id) {
const getTodo = docRef => {
setTimeout(() => {
docRef = this.afs.collection("products").doc(id);
docRef.get().subscribe((doc) => {
if (doc.exists) {
let data = doc.data();
return data;
} else {
console.log("No document.");
return false;
}
});
}, 2000)
}
getTodo(todo => {
console.log('todo', todo)
})
const modal = await this.modalCtrl.create({
component: AdminProductPage,
'id': id,
});
await modal.present();
}
There is something wrong with your "getTodo". Probable you are logging empty data with your code, I can give you the proper functional example:
myData
editProduct() {
this.afs.collection("products").doc(id)
.valueChanges()
.subscribe(data => {
console.log(data)
myData = data
})
}
getData() {
console.log(this.myData) // You will log it twice with this line
}
GOOGLE EXAMPLE
docRef.get().then((doc) => {
if (doc.exists) {
console.log("Document data:", doc.data());
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch((error) => {
console.log("Error getting document:", error);
});
https://firebase.google.com/docs/firestore/query-data/get-data?hl=es
I'm learning to use MongoDB by creating a simple blog app. However, a portion of my code that saves a given post seems to give problems with promises occasionally, but not always, and whether the code succeeds simply seems to be luck.
Each post in my database is stored with the following schema:
{
title: String,
author: String,
body: String,
slug: String,
baseSlug: String,
published: { type: Boolean, default: false }
}
The slug defines the link used to access the blog post, and is automatically generated based upon the title of the blog post. However, if article titles are duplicates, the slug will have a number added to the end to differentiate it from similar articles, while the baseSlug will remain the same. For example:
I create the post "My first post", and it is assigned the baseSlug of "my-first-post". Because no other posts have the same baseSlug, the slug is also set to be "my-first-post".
I create another post called "My first post", and it is assigned the baseSlug of "my-first-post". However, because another post has the same baseSlug, it is assigned the slug "my-first-post-1".
To create this behavior, I wrote the following addpost route in Express:
app.post("/addpost", (req, res) => {
let postInfo = req.body;
for (key of Object.keys(postInfo)) {
if (postInfo[key] == "true") postInfo[key] = true;
}
let slug = postInfo.title
.toLowerCase()
.split(" ")
.filter(hasNumber) // return /\d/.test(str);
.slice(0, 5)
.join("-");
postInfo.slug = slug;
var postData;
Post.find({ baseSlug: postInfo.slug }, (error, documents) => {
if (documents.length > 0) {
let largestSlugSuffix = 0;
for (let document of documents) {
var fullSlug = document.slug.split("-");
var suffix = fullSlug[fullSlug.length - 1];
if (!isNaN(suffix)) {
if (parseInt(suffix) > largestSlugSuffix) {
largestSlugSuffix = suffix;
}
}
}
largestSlugSuffix++;
postInfo.baseSlug = postInfo.slug;
postInfo.slug += "-" + largestSlugSuffix;
} else {
postInfo.baseSlug = postInfo.slug;
}
postData = new Post(postInfo);
})
.then(() => {
postData
.save()
.then(result => {
res.redirect("/");
})
.catch(err => {
console.log(err);
res.status(400).send("Unable to save data");
});
})
.catch(err => {
console.log(err);
res.status(400).send("Unable to save data");
});
});
This code seems to work most of the time, but sometimes it fails, and outputs the following:
TypeError: Cannot read property 'save' of undefined
at C:\Users\User\BlogTest\app.js:94:18
at processTicksAndRejections (internal/process/task_queues.js:94:5)
(For reference, line 94 in my file is postData.save())
I suspect it is because the main body of the function takes longer than it should to execute, and the postData variable is not yet defined. However, postData.save() should not be executed until the promise finishes, because of the .then() callback function.
Why is my code behaving like this? Is there any way to fix it?
The issue is that you are mixing promises with callbacks and closures. That's not how this is intended to work.
When you chain promises, whatever you return in the first promise handler will be added as an input to the next one. And if you return a promise, that promise will be resolved first before being sent to the next thenable.
So you need to return promises from your promises, like this:
app.post("/addpost", (req, res) => {
let postInfo = req.body;
for (key of Object.keys(postInfo)) {
if (postInfo[key] == "true") postInfo[key] = true;
}
let slug = postInfo.title
.toLowerCase()
.split(" ")
.filter(hasNumber) // return /\d/.test(str);
.slice(0, 5)
.join("-");
postInfo.slug = slug;
// var postData; <-- Don't do that
Post.find({ baseSlug: postInfo.slug })
.then((documents) => {
if (documents.length > 0) {
let largestSlugSuffix = 0;
for (let document of documents) {
var fullSlug = document.slug.split("-");
var suffix = fullSlug[fullSlug.length - 1];
if (!isNaN(suffix)) {
if (parseInt(suffix) > largestSlugSuffix) {
largestSlugSuffix = suffix;
}
}
}
largestSlugSuffix++;
postInfo.baseSlug = postInfo.slug;
postInfo.slug += "-" + largestSlugSuffix;
} else {
postInfo.baseSlug = postInfo.slug;
}
return new Post(postInfo);
// We could actually have called postData.save() in this method,
// but I wanted to return it to exemplify what I'm talking about
})
// It is important to return the promise generated by postData.save().
// This way it will be resolved first, before invoking the next .then method
.then( (postData) => { return postData.save(); })
// This method will wait postData.save() to complete
.then( () => { res.redirect("/"); })
.catch( (err) => {
console.log(err);
res.status(400).send("Unable to save data");
});
});
It can be greatly simplified with async/await:
app.post("/addpost", async (req, res) => {
try {
let postInfo = req.body;
for (key of Object.keys(postInfo)) {
if (postInfo[key] == "true") postInfo[key] = true;
}
let slug = postInfo.title
.toLowerCase()
.split(" ")
.filter(hasNumber)
.slice(0, 5)
.join("-");
postInfo.slug = slug;
let documents = await Post.find({ baseSlug: postInfo.slug });
if (documents.length > 0) {
let largestSlugSuffix = 0;
for (let document of documents) {
var fullSlug = document.slug.split("-");
var suffix = fullSlug[fullSlug.length - 1];
if (!isNaN(suffix)) {
if (parseInt(suffix) > largestSlugSuffix) {
largestSlugSuffix = suffix;
}
}
}
largestSlugSuffix++;
postInfo.baseSlug = postInfo.slug;
postInfo.slug += "-" + largestSlugSuffix;
} else {
postInfo.baseSlug = postInfo.slug;
}
let postData = new Post(postInfo);
await postData.save();
res.redirect("/");
} catch (err) {
console.log(err);
res.status(400).send("Unable to save data");
};
});
You are mixing callbacks and promises and while it may do something, I'm not sure what it will do exactly. You should pick one or the other and not mix them as much as possible. I would recommend picking promises if you are using a language that supports async/await, otherwise callbacks.
So for example your outter handler could be an async function
app.post("/addpost", async (req, res) => {
//...
})
Your real bug is in handling Post.find you are handling it somewhat with a callback and somewhat with a promise, and probably whats happening is that its random which one will get called first the callback or the promise resolution. Instead of both you should just do this now that you have an async function:
try {
const posts = await Post.find({ baseSlug: postInfo.slug });
// stuff you were doing in the callback
const post = new Post(postInfo)
// Now the promise code
await post.save()
// success!
res.redirect("/");
} catch (err) {
// With an async function you can just catch errors like normal
console.log(err);
res.status(400).send("Unable to save data");
}
If you're not using webpack or typescript and cannot target es7 then and thus cannot use async/await then I would recommend just using callbacks, do not use .then or .catch and that would look more like:
function error(err) {
console.log(err)
res.status(400).send("Unable to save data")
}
Post.find({ baseSlug: postInfo.slug }, (err, documents) => {
if (err) return error(err)
// stuff you're doing in the callback now
const post = new Post(postInfo)
post.save((err) => {
if (err) return error(err)
// success!
res.redirect("/");
})
})
// delete function
delete =(index) => {
const st = this.state.data;
const newSt = st[index]._id;
// fetch delete api
fetch(`http://localhost:4000/users/${newSt}`, {
method: 'DELETE'
}, (err,result) => {
if(err){
console.log(err)
}else{
result.json({'msg': 'ok'})
}
})
st.splice(index,1)
this.setState({data: st})
}
I just created a delete function for my react-express-mongoose app. but the (err,result) isnt working. What did I do wrong? (the delete function works) I am just confused about the {(err,result) => {...} and what should I do inside it.
I believe fetch is a promise so it needs the following syntax
fetch(opts)
.then(result => {
console.log(result);
})
.catch(err => {
console.error(err);
});
Fetch API: Using Fetch
Please make your function like the following structure.
// delete function
delete =(index) => {
const st = this.state.data;
const newSt = st[index]._id;
// fetch delete api
fetch(`http://localhost:4000/users/${newSt}`, {method: 'DELETE'}).then((res) => { console.log(res); })
, (err,result) => {
if(err){
console.log(err)
}else{
result.json({'msg': 'ok'})
}
})
st.splice(index,1)
this.setState({data: st})
}
spliced.forEach((v) => {
const val = v.split(',') //.slice(0, -2)
formData.devID = val[0];
formData.mobileno = val[1].slice(0, -1);
//const cleanVal = [val[0], val[1].slice(0, -1)];
req.body = formData;
device.validate(formData, req.user, req.app.db.models, (error, result) => {
let errorArr, resultArr = [];
if (error) {
errorArr.push(error)
};
if (result) {
resultArr.push(result)
};
if (errorArr) {
res.status(200).send({
errors: [error]
});
} else {
const formDataFull = new req.app.db.models.Device(formData);
req.app.db.models.Device.bulkWrite([{
insertOne: {
formDataFull
}
},
{
ordered: false
}
])
.then(function(device) {
console.log("created device err,", device);
workflow.emit('response');
res.status(200).send({
success: true
});
})
.catch(function(err) {
console.log("in catch err", err);
if (err.code == 11000) {
workflow.outcome.errors.push("Device Id already exists.");
return workflow.emit('response');
} else return workflow.emit('response', err);
});
}
})
})
spliced is an array of CSV values. so in the above code, only the last object i.e. {formData} is saved. what way should i modify my code so that foreach saves every element and not just last.
Okay so this problem was solved simply by using for-loop. Some people answered using loops and map but sadly none of it worked for me. Maybe my code implementation was wrong. Nevertheless using simple for loop saved the day. thank you all.
PS. This can work if you use a counter to track the callbacks and doing the computation after counter equals the number of parameters in callback.