Object values to array, then replace, not a function? - javascript

So I am using Vue.js, which is not the problem I know, it is just something I'm doing wrong, and there is a reason I'm doing it this way, but I keep getting an error like its not an array.
Code:
methods: {
async register() {
this.errors = '';
this.success = '';
await RegisterService.insertUser(this.email, this.username, this.password, this.passwordTwo)
.then(data => {
if (data.data) {
let v = Object.values(data.data);
console.log(v);
v = v.replace(/["[]]/g, '');
this.errors = v;
} else {
this.success = `Registration Successful!`;
}
});
}
}
So what I am getting is v.replace is not a function, I'm sure there is a simple reason for this and I am just whiffing at figuring it out.

Related

Something Wrong With My Asynchronous JavaScript Code

class Main {
constructor() {
this.argument = process.argv.splice(2);
this.fileToCopy = this.argument[0];
this.destination = this.argument[1] ? this.argument[1] : '';
this.callAdress = process.cwd();
this.finalAdress = `${this.callAdress}\\` + this.destination;
//Problematic Part
if(this.fileExists(this.fileToCopy, this.finalAdress)) console.log("EXISTS")
else console.log("DOESNT EXISTS");
}
async fileExists(file, path) {
try {
let files = await fs.readdir(path);
return files.includes(file);
} catch(e) {
console.log("ERROR", e)
return false;
}
}
}
im trying to check if file exists in directroy, using promises for fs,the problematic part always returns true. im out of ideas.
You call if (this.fileExists...) which is equivalent to if (true) because this.fileExists always return a Promise, which would be implicitly coerced to boolean value of true
So you should call fileExists with await instead, and wrap this call in an IIFE function
And remember to put a semicolon at the beginning of IIFE function to avoid concatnating with the previous line (this.destination(async...))
class Main {
constructor() {
this.argument = process.argv.splice(2)
this.fileToCopy = this.argument[0]
this.destination = this.argument[1] ? this.argument[1] : ''
this.callAdress = process.cwd()
this.finalAdress = `${this.callAdress}\\` + this.destination
;(async () => {
if (await this.fileExists(this.fileToCopy, this.finalAdress))
console.log('EXISTS')
else console.log('DOESNT EXISTS')
})()
}
async fileExists(file, path) {
try {
let files = await fs.readdir(path)
return files.includes(file)
} catch (e) {
console.log('ERROR', e)
return false
}
}
}

Cannot read property 'length' of undefined...Although the object is defined

First I have the following code section:
export default class Recipe {
constructor(recID) {
this.RecipeID = recID;
}
async GetRecipe() {
try {
let Result = await Axios(
`https://forkify-api.herokuapp.com/api/get?rId=${this.RecipeID}`
);
this.Tilte = Result.data.recipe.title;
this.Author = Result.data.recipe.publisher;
this.Image = Result.data.recipe.image_url;
this.Url = Result.data.recipe.source_url;
this.Ingredients = Result.data.recipe.ingredients;
this.PublisherUrl = Result.data.recipe.publisher_url;
this.Rank = Result.data.recipe.social_rank;
} catch (error) {
alert(error);
}
}
CalculateTime() {
try {
this.Time = Math.ceil(this.Ingredients.length / 3) * 15; // error is here
} catch (error) {
console.log(this.RecipeID + ": Length Error->"+error);
}
}
}
Then I call the above code in a separate file like:
import Recipe from "./Recipe";
const RecipeController = async () => {
const ID = window.location.hash.replace("#", "");
if (ID) {
AppState.Recipe = new Recipe(ID);
try {
await AppState.Recipe.GetRecipe();
AppState.Recipe.CalculateTime();
console.log(AppState.Recipe);
} catch (error) {
alert(error);
}
}
};
Now as shown in the following image, that I do get the response of the request & promised is resolved plus there are elements in the 'ingredients' array but sometimes I still get the error "cannot read property 'length' of undefined" when I call the 'CalculateTime()' although the array is now defined and sometimes I don't get any error & it works perfectly fine.Why this random behavior? Even the IDs in the JSON response & the error I logged match i.e. 47746.
This is one reason why having too many try/catches can obscure the causes of errors, making debugging difficult. The problem can be reduced to the following:
class Recipe {
constructor(recID) {
this.RecipeID = recID;
}
async GetRecipe() {
let Result = await fetch(
`https://forkify-api.herokuapp.com/api/get?rId=47746`
).then(res => res.json());
console.log(Result); // <----- look at this log
this.Tilte = Result.data.recipe.title;
// on the above line, the error is thrown
// Cannot read property 'recipe' of undefined
}
}
const r = new Recipe();
r.GetRecipe();
See the log: your Result object does not have a .data property, so referencing Result.data.recipe throws an error. Try Result.recipe instead:
class Recipe {
constructor(recID) {
this.RecipeID = recID;
}
async GetRecipe() {
let Result = await fetch(
`https://forkify-api.herokuapp.com/api/get?rId=47746`
).then(res => res.json());
const { recipe } = Result;
this.Tilte = recipe.title;
this.Author = recipe.publisher;
this.Image = recipe.image_url;
this.Url = recipe.source_url;
this.Ingredients = recipe.ingredients;
this.PublisherUrl = recipe.publisher_url;
this.Rank = recipe.social_rank;
}
CalculateTime() {
this.Time = Math.ceil(this.Ingredients.length / 3) * 15; // error is here
console.log('got time', this.Time);
}
}
(async () => {
const r = new Recipe();
await r.GetRecipe();
r.CalculateTime();
})();
Unless you can actually handle an error at a particular point, it's usually good to allow the error to percolate upwards to the caller, so that the caller can see that there was an error, and handle it if it can. Consider changing your original code so that RecipeController (and only RecipeController) can see errors and deal with them - you can remove the try/catches from the Recipe.
Are you sure some of the responses are not missing ingredients? And calculateTime is always called after getRecipe?
I would add a condition or fallback to prevent errors, as in.
this.Time = Math.ceil((this.Ingredients || []).length / 3) * 15;
I would speculate that this "random" behavior can be related to asynchronous code. You need to ensure that the class has Ingredients in place before you calculate. I have a feeling that you should try changing your syntax to a Promise handling using .then() and .catch(), especially since you already use try/catch in your code. This approach will ensure proper resolution of Promise on axios request, and will eliminate "randomness", because you will have a better control over different stages of Promise processing.
let Result = await Axios(
`https://forkify-api.herokuapp.com/api/get?rId=${this.RecipeID}`
)
.then((data) => {
this.Tilte = data.data.recipe.title;
this.Author = data.data.recipe.publisher;
this.Image = data.data.recipe.image_url;
this.Url = data.data.recipe.source_url;
this.Ingredients = data.data.recipe.ingredients;
this.PublisherUrl = data.data.recipe.publisher_url;
this.Rank = data.data.recipe.social_rank;
this.Ingerdients = data.data.recipe.ingredient;
}
.catch((err) => {
console.log(err);
return null;
});

Javascript: How to check if async operation is still pending / In progress?

I would like to know if it is somehow possible to check if an asynchronous operation in Javascript is still pending..
Because I am doing a database request on calling a specific URL... While the db call is still in progress, I want to stop any other incoming db-calls (which means, stop any further calls to that URL in case the db-request is still pending).
Is that somehow possible?
Because the database call takes up to minutes, and I don't want to launch another database-call while the first is still in progress.. The problem is, I somehow cannot figure out how to check if the call has started and is still in progress, because the response comes only after the .then() clause when the process has already finished.
this is my db-call function:
const getWriteIndex = async () => {
return Promise.all(someFunction1, someFunction2...).then(...) {
writeMessageObject = checkDocuments(...);
return Promise.resolve(writeMessageObject);
})).catch((err) => {
return Promise.reject(err);
});
}
This is my URL/Route Call function with express:
router.get("/v1/...", someMiddleware(), async function(req,res,next) {
if (read_cached() && initialised_read) {
res.setHeader('Content-Type', 'application/json');
res.json(readmsg_obj);
} else {
try {
//HOW CAN I CHECK HERE IF THE DB-CALL IS ALREADY IN PROGRESS?
readmsg_obj.message = '';
getReadIndex().then((message) => {
initialised_read = true;
readmsg_obj = {...message};
res.setHeader('Content-Type', 'application/json');
res.json(readmsg_obj);
}).catch((reject) => {
logger.error(`/../... : ${reject}`);
initialised_read = false;
res.status(500).send(reject);
});
} catch(err) {
logger.error(`/v1/... : ${err}`);
res.status(500).send(err);
};
}
});
hmm I found a workaround here:
https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved
so I wrote that function to check for promise stati, but I am still wondering if it's not somehow possible to query for static promise properties to get their actual state ;) (but weirdly, I didn't find any on the web).
const checkPendingRequest= (promise) => {
if (promise.isResolved) return promise;
// Set initial state
var isPending = true;
var isRejected = false;
var isFulfilled = false;
// Observe the promise, saving the fulfillment in a closure scope.
var result = promise.then(
function(v) {
isFulfilled = true;
isPending = false;
return v;
},
function(e) {
isRejected = true;
isPending = false;
throw e;
}
);
result.isFulfilled = function() { return isFulfilled; };
result.isPending = function() { return isPending; };
result.isRejected = function() { return isRejected; };
return result;
}
So I fixed my function for the request:
router.get("/v1/...", someMiddleware(), async function(req,res,next) {
if (read_cached() && initialised_read) {
res.setHeader('Content-Type', 'application/json');
res.json(readmsg_obj);
} else {
try {
readmsg_obj.message = '';
if ((dbQueryPromiseRead != null) && dbQueryPromiseRead.isPending()) {
logger.info(`Database request for Index-read is still pending!`);
return;
}
dbQueryPromiseRead = checkPendingRequest(getReadIndex());
dbQueryPromiseRead.then((message) => {
initialised_read = true;
readmsg_obj = {...message};
res.setHeader('Content-Type', 'application/json');
res.json(readmsg_obj);
}).catch((reject) => {
logger.error(`/../... : ${reject}`);
initialised_read = false;
res.status(500).send(reject);
});
} catch(err) {
logger.error(`/v1/... : ${err}`);
res.status(500).send(err);
};
}
});
You need to try add in node.js like global.dbCallState flag if operation is still running.
This global var one for all modules.
Do not change this object like global = new Object();, but you can use child field's.
https://nodejs.org/api/globals.html
You can change it in another module like global.dbCallState = false.
It not best solution, but it can help.
But i don't know, why you want only one connection. Its not good solution to block I/O in node.js

Firestore: reference type.How wait for all get() call of evey result

I am getting an Observable Ticket[]> from a firestore DB, one field in ticket is reference type.
When I subscribe for results I use:
getTickets()
.subscribe(listOfTickets=> {
//loop the array
listOfTickets.forEach(ticket => {
ticket.personRef.get() //this is the reference type field
.then(res => { //getting information
let person = res.data();
}
}
....
}
How can I wait for all the results in:
ticket.personRef.get()
I am trying using forkJoin, but I still do not understand how apply to this. The observable listOfTickets has a lot of results.
Do not use forEach. Use for
async someFunction() {
getTickets().subscribe(async listOfTickets => {
const allTickets = [];
for (let i = 0; i < listOfTickets.length; i++) {
await listOfTickets [i].personRef.get().then(snapshot => {
return snapshot.data();
}).then(ticket => {
allTickets.push(ticket);
})
}
console.log(allTickets);
})
}
Thanks, your help point me in the right direction to solve the problem with just some little changes, this is the final code:
async someFunction() {
getTickets()
.subscribe(async listOfTickets => {
const allTickets = [];
var ticket = null;
for (let i = 0; i < listOfTickets.length; i++) {
await listOfTickets[i].personRef.get().then(snapshot => {
ticket = snapshot.data();
})
allTickets.push(ticket);
}
}

Maximum call stack size exceeded with 2 Collection.find

I'm using Angular2 and Meteor. I have an exception(Maximum call stack size exceeded) in my Chrome console since I added that code in my client side:
var userChannelsId = UserChannels.find({idUser: Meteor.userId()});
this.channels = Channels.find({_id: {$in: userChannelsId}});
From what I found, this exception occurs when there is an infinite loop. I'm sure the error comes from this lines (I debugged my code until I was sure).
Is the problem coming from the fact that the first search isn't finished when the second begin ?
All function :
getChannelList(): void {
console.log('ok');
var userChannelsId = UserChannels.find({idUser: Meteor.userId()});
this.channels = Channels.find({_id: {$in: userChannelsId}});
console.log('ko');
this.channels.subscribe(channel => {
this.selectChannel(channel[0]);
});
}
EDIT:
As #MichaelSolati I tried to get only the IdChannel of the userChannel, but I still have the same error ... It returns an observable and not an array. Maybe it's the problem? This is what I did:
getChannelList(): void {
console.log('ok');
let userId = Meteor.userId();
var userChannelsId = UserChannels.find({idUser: userId});
var values = userChannelsId.map((userChannels:Array<UserChannel>) => {
let result:Array<String> = [];
if (userChannels) {
userChannels.forEach((userChan) => {
result.push(userChan.idChannel);
});
}
return result;
});
this.channels = Channels.find({_id: {$in: values}});
console.log('ko');
this.channels.subscribe(channel => { this.selectChannel(channel[0]); });
}
Updated because of the use of MeteorRxJS for the queries. While it's likely not perfect, it should probably put you on the right path.
private userChannelsSub: Subscription;
getChannelList(): void {
console.log('ok');
let userId = Meteor.userId():
let this.userChannelsSub = UserChannels.find({idUser: userId}).subscribe((userChannels: any[]) => {
if (Array.isArray(userChannels)) {
let userChannelsId = userChannels.map((channel: any) => { return channel._id; });
if (this.channels) { this.channels.unsubscribe(); }
this.channels = Channels.find({_id: {$in: userChannelsId}}).subscribe((channels: any[]) => {
this.selectChannel(channels[0]);
});
}
});
console.log('ko');
}
Alright guys,
I found a solution that works pretty well !
If you have any suggestion to improve my proposition, fill free to comment, I would appreciate it :)
getChannelList(): void {
let userId = Meteor.userId();
UserChannels.find({idUser:userId}).subscribe((userChannel:UserChannel[]) =>{
var channelsId:Array<String> = [];
userChannel.forEach((userChan)=>{
channelsId.push(userChan.idChannel);
});
this.channels = Channels.find({_id: {$in: channelsId}});
});
if(this.channels !== undefined) {
this.channels.subscribe(channel => {
this.selectChannel(channel[0]);
});
}
}
Thank you all for your answers.

Categories