issue refer to scope of variable - react-native

how to get variable from outer layer method
trying to use a variable in outer layer in my React-Native App
updateCheckBox() {
Constants.TABS.map((item) => {//Constants.TABS is an array
AsyncStorage.getItem(item)//using item as key to fetch from AsyncStorage
.then((res) => {
if(res == 1) {
//debugged here, item was undeined. but i need setState here with item as key. How should i get item here.
this.setState({item: true}) // I need to get the item here, but it show undefined
} else {
this.setState({item:false}) // I need to get the item here, but it show undefined
}
})
})
}
// I need to get the item here, but it show undefined

You need to wrap the item in [] to use it as a key for a property. Like this:
updateCheckBox() {
Constants.TABS.map(item => {
AsyncStorage.getItem(key) //
.then((res) => {
//item is accessible here, to use item as the key to a property wrap it in []
if(res == 1) {
this.setState({[item]: true});
} else {
this.setState({[item]: false});
}
})
})
}

finally, I found there is no issue in this code, the thing is
updateCheckBox() {
Constants.TABS.map((item) => {
let key = item
AsyncStorage.getItem(key)
.then((res) => {
console.log(item, "item is here", res); //item is visible here
console.log(key) //key is all always undefined
if(res == 1) {
this.setState({item: true})
} else {
this.setState({item:false})
}
})
})
}
key is not visible in method then, which I can not explain, but all in all, my code works.

Related

Vuex passing different arrays

Making a filter:
Mutations
export default {
state: {
filteredBrands: []
},
mutations: {
showFilteredList(state, payload) {
state.filteredBrands.push(payload);
}
}
};
Methods
loadProducts(item) {
axios.get('/api', {
params: {
per_page: 20,
filter_machinery_brands: [ item ]
}
})
.then((response) => {
this.$store.commit(
'showFilteredList',
response.data
);
});
},
item this is an input with a checkbox, when clicked, a request is made to the server for this category
For some reason, the push does not work, why?
And I would like there to be a check, if the array is the same, then delete, otherwise add. Is it possible?
If you can se an array comes in as payload. Then you are trying to push an array into an array. Which cant be done in either js or ts.
You can try set the value:
state.filteredBrands = payload;
otherwise you would have to do something like this:
state.filteredBrands.push(payload[0]);
If you wanna control for existing items in array, and assuming your are not always setting value, but pushing new values into your array. You can do something like this:
if (state.filteredBrands.indexOf(payload[0]) === -1) {
// Not in array
state.filteredBrands.push(payload[0])
} else {
// is allready in array
state.filteredBrands.forEach((item, index) => {
if (item === payload[0]) {
state.filteredBrands.splice(index, 1)
}
})
}
EDIT:
My assumption was right.
Your payload is an array
Your state is an array
-------> You are trying to push payload(array) into state(array) - which cant be done i js - This solution would after my suggestion be more clean:
payload.forEach((value, index) => { // Looping payload
if (state.filteredBrands.indexOf(value) === -1) {
state.filteredBrands.push(value) // push if value not allready in array
} else {
state.filteredBrands.splice(index, 1) // if value is in array -> remove
}
})
Yes, you can push an array into an array.
I guess the problem here is your vuex config.
Vuex state is a function, so it needs to be:
state () {
return {
filteredBrands: []
}
}
And if you are using Nuxt:
export const state = () => ({
filteredBrands: []
})

Is it good practice to use for loops to sort out data in the same function where it's fetched in Vue?

I am using fetch to get some data from an API, I convert this to JSON and want to sort it into different categories. For example tickets (which is what I'm retrieving) with the status active should be in a different array than the ones with status waiting on customer. I want to use a for loop to sort through the results. Should I do this in the same function they're fetched in?
Did a bit of googling but couldn't find a post on this.
methods: {
fetchTickets() {
fetch('/api')
.then(res => res.json())
.then(resJson => {
arrayLength = resJson.length
for(var i = 0; i < arrayLength; i++) {
if(resJson[i]['status'] === 'active') {
//do something
}
else if(resJson[i]['status'] === 'waiting on customer') {
// do something else
}
else {
// do a dance
}
}
});
},
}
So, is it okay to do the above or is it very sensitive to errors/is there a more convenient alternative?
There is a more convient alternative.
You should create two API calls.
1.) /api/activeUsers
2.) /api/waitingCustomers
Then for each API call, you can use the .filter API and return the appropiate array
fetchActiveTickets() {
fetch('/api')
.then(res => res.json())
.then(resJson => {
return resJson.filter(item => {
return item.status ==='active'
})
//do the same for waiting... i.e. resJson(item => {
//return item.status ==='waiting'
//})
}
});
},
I would recommend using .filter() rather than looping over the array to split the source into the pieces you want.
data: {
activeTickets: [],
waitingTickets: []
}
methods: {
fetchTickets() {
fetch('/api')
.then(res => res.json())
.then(resJson => {
this.activeTickets = resJson.filter(function(ticket) { return ticket.status === 'active' });
this.waitingTickets= resJson.filter(function(ticket) { return ticket.status === 'waiting on customer' });
// do things with your filters arrays...
});
},
}
Try
methods: {
async fetchTickets() {
let res = await (await fetch('/api')).json();
let active = res.filter(x=> x['status']=='active');
let waiting = res.filter(x=> x['status']=='waiting on customer');
// ... do something
},
}

Using set() for computed values correctly in Vue

I'm having an issue with setting a computed property (which is an array). I have the following computed property in my Vue component:
posts: {
get () {
if ( this.type == 'businesses' || this.type == 'business' ) {
return this.$store.getters.getAllBusinesses.map(_business => {
return _business
})
} else if ( this.type == 'shops' || this.type == 'shop' ) {
return this.$store.getters.getAllShops.map(_shop => {
return _shop
})
} else if ( this.type == 'events' || this.type == 'event' ) {
return this.$store.getters.getAllEvents.map(_event => {
return _event
})
} else {
return this.$store.getters.getAllBusinesses.map(_business => {
return _business
})
}
},
set (posts) {
console.log(posts)
this.posts = posts // Doesn't work - this causes a maximum call stack error, recursively setting itself obviously.
return posts // Doesn't work either - this.posts doesn't seem to be changing...
}
},
The console.log(posts) is exactly what I want - a filtered array of posts, see the below console log output.
My question is simply this: how do I go about updated the computed posts value?
If it is useful, I am doing the following manipulation to the posts:
let filteredPosts = []
this.posts.filter(_post => {
_post.category.forEach(category => {
if ( this.categoryFilters.includes(category.slug) ) {
filteredPosts.push(_post)
}
})
})
let uniqueFilteredPosts = [...new Set(filteredPosts)];
this.posts = uniqueFilteredPosts
This is purely to filter them. What I am console.logging is absolutely correct to what I want. So this might be a red herring.
Any pro-Vue tips would be greatly appreciated!
If you want to use a computed setter, you normally assign to whatever values underlie the computed's get function. See the example at the link.
In your case, you examine this.type and return something from the store based on it. The setter should probably examine this.type and set something in the store based on it.

Array of unique objects in react native

There is a method to store an array of objects for question id as key and answer as a value.
But it is creating multiple objects of same question id because of saving the previous state of object.
handleSelect(questionId,index,value){
this.setState((oldState)=>({selectedOptions:[...oldState.selectedOptions,{question:questionId,answer:value}]}))
}
How can i create unique array of objects?
You can achieve this in a number of ways - one way might be to use the Array#reduce() method like so:
handleSelect(questionId,index,value) {
// Your array containing items with duplicate questions
const arrayWithDuplicates = [
...this.state.selectedOptions,
{ question:questionId,answer:value }
];
// Use reduce to create an array of items with unique questions
const selectedOptions = arrayWithDuplicates
.reduce((uniqueArray, item) => {
const isItemInUniqueArray = uniqueArray.find(uniqueItem => {
return uniqueItem.question === item.question;
});
if(!isItemInUniqueArray) {
uniqueArray.push(item);
}
return uniqueArray
}, [])
this.setState((oldState)=>({selectedOptions: selectedOptions}))
}
This thread is closed now. I got the solution for my problem.
handleSelect(questionId,index,value) {
let question = this.state.selectedOptions.find((questions) => {
return questions.question === questionId
});
if(question){
this.setState(prevState => ({
selectedOptions: prevState.selectedOptions.map(
obj => (obj.question === questionId ? Object.assign(obj, { answer: value }) : obj)
)
}));
}
else{
this.setState((oldState)=>({selectedOptions:[...oldState.selectedOptions,{question:questionId,answer:value}]}))
}
}

How to call a post method from api in a loop Angular

I am trying to do a put request to an api from array that I have. The post wants an object, and I have an array of objects. What I do is a loop itereting the length of my array of objects calling the method into my service. The problem is that just works the first one and the rest are not working. Do I should something like return promise and then call it recursively?
Here I let my method to call the api:
onUpdate() {
for (var i = 0; i < this.conditionsToUpdate.length; i++) {
this.ruleService.updateConditionsFromRule(this.rule.id, this.conditionsToUpdate[i])
.then(_ => {
this.notificationService.addToast('Condition Updated!', '', 2)
})
.catch(err => this.notificationService.handleError("Could not update the
condition!"))
}
}
Finally, on my Service I have my request:
updateConditionsFromRule(idRule: number, condition: ConditionUpdate):Promise<any> {
return this.http.post(`${this.organizationId}/rules/${idRule}/conditions`, condition)
.toPromise()
.then(res => {
const response = <{ id: String, error: IError[] }>res.json();
if (!!response && !!response.error) {
return Promise.reject(response.error)
} else {
return Promise.resolve(response)
}
}).catch(err => Promise.reject(err));
}
And as I said, it just returns me the first post we do, the rest are not being created.
Thank you a lot!
You can use Observable for this, promises will be too limited.
given your array updateConditionsFromRule, this is how to implement such a thing:
let requests:Observable<Response>[] = [];
updateConditionsFromRule.forEach( updateCondition => {
requests.push(this.http.post(`${this.organizationId}/rules/${idRule}/conditions`, condition));
});
// After our loop, requests is an array of Observables, not triggered at the moment.
//Now we use combineLatest to convert our Observable<Response>[] to a Observable<Response[]>.
//This means that the promise will resolve once the last request of the array has finished.
Observable.combineLatest(requests).toPromise()
.then(res => {
const response = <{ id: String, error: IError[] }>res.json();
if (!!response && !!response.error) {
return Promise.reject(response.error)
} else {
return Promise.resolve(response)
}
}).catch(err => Promise.reject(err));
}