Context value getting undefined inside nested Loop - javascript

Below java-script code context value became undefined inside nested loop.but outside the nested loop the values is properly showing.
please help to show the context value inside the loop.
module.exports = function (options = {}) {
return async context => {
const { data } = context;
context.app.service('emplist').find({
query: { empId: { $in: ["12321"] } },
paginate: false,
}).then(result => {
console.log('firstname_Inside-->',context.data.firstname);
}).catch((error) => {
console.log(error);
});
console.log('firstname_Outside-->',context.data.firstname);
return context;
};
};
OUTPUT:-
//here value is undefined
firstname_Inside-->undefined
//here value is properly showing
firstname_Outside-->sam

Looks like context.app.service('emplist').find() call is asynchronous. And it affects the context. So the possible answer would be that context.data object is being cleaned up during context.app.service('emplist').find() work.

Related

Need help understanding the scope of this javascript variable

In javascript, within a VueJS SPA, I'm trying to create a method that will allow me to reduce redundant code by passing the Google Maps Places Service only a place_id and the fields I would like returned.
getPlaceDetails (place, fields) {
this.$refs.mapRef.$mapPromise.then((map) => {
var placesServices = new window.google.maps.places.PlacesService(map)
placesServices.getDetails({ placeId: String(place.place_id), fields: fields }, (result, status) => {
if (status === window.google.maps.places.PlacesServiceStatus.OK) {
alert(JSON.stringify(result))
return result
}
})
})
}
I'm calling the above method from within another method:
var place = this.getPlaceDetails(place, ['name', 'geometry', 'place_id'])
It is invoked successfully... and the alert shows the desired JSON.. but place is null. I've tried using
var vm = this
above
var placesServices
and assigning the result to an app level variable... even inside of a .then after the first promise... like so:
getPlaceDetails (place, fields) {
this.$refs.mapRef.$mapPromise.then((map) => {
var vm = this
var placesServices = new window.google.maps.places.PlacesService(map)
placesServices.getDetails({ placeId: String(place.place_id), fields: fields }, (result, status) => {
if (status === window.google.maps.places.PlacesServiceStatus.OK) {
alert(JSON.stringify(result))
vm.tempPlace = result
}
})
}).then(function () {
return this.tempPlace
})
}
How can I get the method to return the result object??
Promises
A promise is an object that will resolve (or reject) in some point in the future. This is necessary to execute asynchronous tasks (e.g. http-calls) that take an undefined amount of time to finish.
Promises can be chained i.e. get executed one after another. This is what the .then method does. With .then you pass a function that will be executed as soon as the promise is finished. This function will receive the object that was returned by the previous promise.
Your method
getPlaceDetails (place, fields) {
return this.$refs.mapRef.$mapPromise.then((map) => {
var vm = this;
var placesServices = new window.google.maps.places.PlacesService(map);
placesServices.getDetails({ placeId: String(place.place_id), fields: fields }, (result, status) => {
if (status === window.google.maps.places.PlacesServiceStatus.OK) {
alert(JSON.stringify(result));
return result;
}
});
});
}
This Method will return a promise that - at some point in the future - will yield the desired result.
When you want to call the method you get that promise and have to handle it, again by passing a function (using .then) that will be executed once the result is ready.
this.getPlaceDetails(...).then((result) => {
// handle your result
}}
Alternatively you could use the await operator to wait until the promise is finished:
var place = await this.getPlaceDetails(...);
Instead of returning the data, you may consider assigning the JSON to a Vue watched data variable, like so:
var somePlace = new Vue({
el: '#someEl',
data: {
message: 'Hello robwolf.io',
tempPlace: {} // <- variable waiting for your asynchronous data if it comes thru
},
methods: {
getPlaceDetails (place, fields) {
// [...your promise code here...]
}).then((result) => {
this.tempPlace = JSON.stringify(result)
// return this.tempPlace
})
// [...the .then function must also be an arrow function to have scope access to tempPlace...]

How to create multiple copies of a deeply nested immutable Object?

I'm trying to get data from firebase/firestore using javascript so i made a function where i get my products collection and passing this data to reactjs state.products by setState() method
My goal is to pass these products to my react state but also keeping the original data and not changing it by manipulating it. I understand that in JavaScript whenever we are assigning the objects to a variable we are actually passing them as a reference and not copying them, so that' why i used the 3 dots (spread syntax) to copy firestore data into tempProducts[] same way to copy it in virgins[]
getData = () => {
let tempProducts = [];
let virgins = [];
db.collection("products")
.get()
.then(querySnapshot => {
querySnapshot.forEach(item => {
const singleItem = { ...item.data() };
virgins = [...virgins, singleItem];
tempProducts = [...tempProducts, singleItem];
});
tempProducts[0].inCart = true;
this.setState(
() => {
return { products: tempProducts };
},
() => {
console.log(
"this.state.products[0].inCart: " + this.state.products[0].inCart
);
console.log("tempProducts[0].inCart: " + tempProducts[0].inCart);
console.log("virgins[0].inCart: " + virgins[0].inCart);
}
);
});
};
then calling this method in componentDidMount
componentDidMount() {
this.getData();
}
So I changed the first product inCart value in tempProducts to true when I console log tempProducts value and state.products value it gives me true all fine but I'm expecting to get false when i console log virgins value but i did not. I should also mention that all inCart values are false in firestore data.
I solved the issue by passing the original firestore data to virgins[] instead of the singleItem as it is an object referenced by tempProducts[] like so virgins = [...virgins, item.data()]; also it works if i copied the singleItem object instead of referencing it like so virgins = [...virgins, { ...singleItem }]; keep in mind that i have no idea if this solutions are in fact efficient (not "memory waste") or not.

Having an issue with my Vuex getter sending a 0 length Array that has items inside when expanded in the console [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Why does console.log wrongly print an empty array?
(1 answer)
Closed 3 years ago.
I am using Vuex to call a Django API for count data.
state: {
DailyCycleDate: []
},
getters: {
DailyCycleDate : state => {
console.log('Getter')
console.log('Length of Array: '+state.DailyCycleDate.length)
console.log(state.DailyCycleDate)
return state.DailyCycleDate
}
},
mutations: {
DailyCountMutation(state, DailyCount) {
const NewPatientMap = new Map(Object.entries(DailyCount));
let NewList = []
NewPatientMap.forEach((value, key) => {
var NewPatientCycle = value['Current_Cycle_Date']
console.log('inside mutation')
state.DailyCycleDate.push(NewPatientCycle)
});
}
},
actions: {
DailyCountAction ({ commit }) {
axios({
method: "get",
url: "http://127.0.0.1:8000/MonthlyCountByDay/",
auth: {
username: "test",
password: "test"
}
}).then(response => {
commit('DailyCountMutation', response.data)
}).catch((error) => {
console.log(error)
})
}}
And for some reason I am returning an empty array in the console log:
My question is, how did this array become empty? Is there a sync issue going on? I've been working with promises and TimeOut methods and nothing has helped. How am I able to see the data I need to see while the array is 0?
Could there be an object inside of the array? I've also tried changing it into a object and mapping it. Any advice is greatly appreciated!
Thanks,
I should also note that I am needing this data to be in the label field of a ChartJS barchart
export default {
extends: HorizontalBar,
data() {
return{
}
},
mounted () {
/* Need to write the API call for chart data here. */
this.$store.dispatch('DailyCountAction')
this.renderChart({
labels: [this.$store.getters.DailyCycleDate],
datasets: [...]
state.DailyCycleDate.push doesn't update state.DailyCycleDate reference.
You need to update reference of state.DailyCycleDate to make getters re-calculated again
mutations: {
DailyCountMutation(state, DailyCount) {
const NewPatientMap = new Map(Object.entries(DailyCount));
let NewList = []
NewPatientMap.forEach((value, key) => {
var NewPatientCycle = value['Current_Cycle_Date']
console.log('inside mutation')
NewList.push(NewPatientCycle)
});
state.DailyCycleDate = state.DailyCycleDate.concat(NewList)
}
}

Typescript - if conditrional inside a map

I am mapping a subset of user data to an object of a refined data set. Inside the map i want to check if a variable is null or undefined, and if yes, then to set this variable to a placeholder value.
The issue I am facing is that declaring an if statement inside the map is causing an error, but even though a map can have an index as a parameter, how can we use it functionally with a conditional Statement? Any insight most appreciated.
return this.UserService.search(url)
.map((data) => {
console.log(data);
data.result = <any> data.result.map((user, index) => ({
// if statement causing error here
if(user.name === null || user.name === undefined){
// error with this if condition
},
id: user.id,
name: user.name,
type: user.type,
password: user.password,
}));
return data;
}).map(data => ({
meta: { totalItems: data.size },
data: data.result,
}));
You're attempting to use an object literal as the return type, but naturally, an if statement (or any statement) can't be inside object literal syntax.
So instead, define a function body, which also uses curly braces, and put your code inside with an explicit return statement.
// Starts function body instead of single expression-v
data.result = <any> data.result.map((user, index) => {
if (some_condition) {
return "some value"; // The object?
} else {
return "other value"; // A different object?
}
/*
// I assume these are to be used in the object you return
id: user.id,
name: user.name,
type: user.type,
password: user.password,
*/
});
You can express conditions in literal maps, but it is somewhat ugly.
return {
a: 1,
...(some_condition && {
b: 1,
})
};
As far as i know you can't do that with JUST a map.
however you could follow it up with a filter() function:
const newArray = oldArray.map((value, index) => condition ? value : null).filter(v => v);
you basicaly iterate over each item and then return the value or null depending on your condition.
Now once you have the map you just filter it by removing the null values from the array.
Notice that the original array is not altered and a new one is returned.
thanks for the idea #user8897421 for the idea. i just wanted to turn it into a one liner.

VueJS return value from promise in method section of component

The function below set the this.personStatus on all components v-bind. How can I make it update a single comm-person component or multiple comm-person components depending on the result of the axios.post?
The template extract for a person is this:
<comm-person
v-for="person in people"
v-show="(!pollActive) || isParticipant(person)"
:participant="pollActive && isParticipant(person)"
:status="personStatus"
:key="person.id"
>
<div class="checkbox-wrap"><input :disabled="pollActive" :value="person" v-model="selectedPeople" type="checkbox"></div>
<div #click="togglePerson(person)" class="name">{{person.given_name}} {{person.family_name}}</div>
<div class="phone-number">{{person.phone}}</div>
</comm-person>
E.G: :status="personStatus"
data() {
return {
pollText: '',
primaryButton: {
border: `2px solid ${iiColor('ii-green')}`,
},
secondaryButton: {
border: `2px solid ${iiColor('ii-grey')}`,
},
people: [],
safeUsers: [],
unsafeUsers: [],
selectedPeople: [],
polledPeople: [],
pollActive: false,
messages: [],
msgType: 'SMS',
personStatus: '?'
};
},
..
..
methods: {
getStatus(person) {
axios.post(`${config.iiApiUrl[process.env.NODE_ENV]}/person/find`, {
id: person.id,
}).then((resp) => {
console.log('handle response...');
console.log(resp.data.ref);
if(resp.data.ref != null) {
if (this.safeUsers.includes(resp.data.ref)) {
console.log('person is safe');
this.personStatus = 'safe';
}
if (this.unsafeUsers.includes(resp.data.ref)) {
console.log('problem with person');
this.personStatus = 'safe';
}
}
else {
return '?';
}
});
},
}
But the this.personStatus from the axios.post call updates all the components. How can I make it update one or two depending on the result?
Please help!!
First of all post returns a promise and it is performed asynchronously. getStatus will return before the anonymous function you pass in to post will be called. It cannot return the string value. For the caller of getStatus() to get the value of the returned string, you must use then(). I suggest you research asynchronous programming and promises in javascript a bit further to understand callbacks and when they are run.
Secondly, you typically should not bind a prop to the result of a method/function. Props almost always should be bound to a data field or computed.
I suggest you change the post handler to set a data field and bind to that instead.
:status="personsStatus"
data: {
return {
person: ??, //i dont know where this comes from
personStatus: 'unknown', //some default value. maybe '?'
};
},
mounted() {
this.loadStatus(this.somePerson);
},
methods: {
loadStatus(person) {
axios.post(...)
.then((resp) => {
//your more complex logic here,
//but instead of returning a string,
//set the personStatus field like the following:
this.personStatus = 'safe';
});
}
}
This may require you to create a child component to do this work if you have multiple person instances.

Categories

Resources