How to iterate an object retrieved by Fetch API in VueJS? - loops

I have a data Object resulting by Fetch:
data () {
return {
show: true,
interval: {},
dadosCliente: {},
radio: ''
}
fetchNome() {
fetch('http://localhost:3000/pessoas/'+this.$store.state.cpf)
.then(response => response.json())
.then(data => {
this.dadosCliente = data
this.show = false;
});
}
Output dadosCliente:
[{'nome':'Paulo'},{'nome':'Marcos'},{'nome':'Victor'}]
When I try to iterate v-for in v-radio (vuetify) I receive message saying which item is not declared.
<v-radio-group v-model="radio" mandatory>
<v-radio :v-for="item in dadosCliente" :key="item.nome" :label="`${item.nome}`"></v-radio>
</v-radio-group>
Speding a time reading some articles, posts, but I couldnt finish it. Anyone can help me ?

You shouldn't use binding sign : with directives like v-if or v-for it should be like:
v-for="item in dadosCliente"

Removing the : will make it work...
To add on ..since you are iterating an array, instead of binding the nome to the key, you can do something like this
<v-radio-group v-model="radio" mandatory>
<v-radio :v-for="(item,index) in dadosCliente" :key="index" :label="`${item.nome}`"></v-radio>
</v-radio-group>
In this way, you can even handle objects with redundant nome values.

Related

Filtering fetched array in render React

New to React here so please bear with me. I fetched a list of data from a server and that I put in the State though the componentDidMount function. In it, I push the data to my State array named solo. It works great until I try to render the array. I need to filter my array to map the data based on one property (categ) matching a property from another array, and create buttons in the right category. When I run my code, I only get one button rendered, whichever is first in my solo array, in which all my data appears. I'm sure it has someting to do with the asynchronous nature of fetch, but I don't understand what.
Here's my code :
componentDidMount(){
// Get URLS from config
const data = this.props.config.layerUrls
// Init state values
let categ = [...this.state.categ]
let solo = [...this.state.solo]
// Loop through categories
for (let i = 0; i < data.length; i++) {
let donneesCateg = data[i]
let listURLS = donneesCateg["urls"]
categ.push({['categ']: donneesCateg["name"], ['type']: "categ", ['urls']: listURLS })
this.setState({ categ : categ })
// Loop through individual URL data
for (let a = 0; a < listURLS.length; a++) {
fetch(listURLS[a] + "?f=pjson")
.then(res => res.json())
.then(data => {
// Push to state array
solo.push({['categ']: donneesCateg["name"], ["type"]: "solo", ["couche"]: data.name, ["url"]: listURLS[a] })
this.setState({ solo : solo })
})
}
}
}
render() {
{
return (
<p className="shadow-lg m-3 p-1 bg-white rounded">
{this.state.categ.length!=0 ? this.state.categ.map(item => {
return (
<div>
<button id={item.categ} className="categ" value={item.urls} onClick={this.selectChangeMultiple}>{item.categ}</button>
{this.state.solo.length!=0 ? this.state.solo.filter(solo => solo.categ == item.categ).map(data =>
<button id={data.categ} className="btn" value={data.url} onClick={this.selectChangeSingle}>{data.couche}</button>
) : <p id="loadingMsg">Solo data Loading...</p>}
</div>
)
}) : <p id="loadingMsg">Categ data Loading...</p>}
</p>
</div>
);
}
}
Note : I have to go through this loop system because the URLs I use to fetch the data are in a JSON in which they are stored by categories.
Many thanks.
In your code, any subsequent call to setState({solo: solo}) isn't recognized as an update by React. This happens because solo is always the same "object" (although mutated with push, but React comparison algorithm doesn't go so far as to compare the new and previous. It just compares the old and new solos with something like ===.
An obvious fix would be to call this.setState({ solo : [...solo] }) instead of this.setState({ solo : solo }), although it would still may cause too many extra rerenders. But it'd be a good start.

Array empty even after a loop

I'm trying to fill an array with some registers from a database. However, even after retrieving said registers and place them into the array, after the loop the array stays empty
const userParties = [];
userFollowing.forEach(element => {
// Here's when I gather the information that I need
dispatchGetUserEvents(element.user, response => {
userParties.push(response);
console.log(userParties); // Here the array is full of elements, like it's supposed to be
});
});
console.log(userParties); // However, here 'userParties' return '[]'
this.setState({ followUsersEvents: userParties });
this.setState({ userImage: userImg });
I tried to update the state array on the loop, but I had no luck there either.
'userParties' is not a state array btw.
const userParties = [];
userFollowing.forEach(element => {
// Here's when I gather the information that I need
dispatchGetUserEvents(element.user, response => {
userParties.push(response);
console.log('dispatchGetUserEvents', userParties); // Here the array is full of elements, like it's supposed to be
});
});
console.log('outside', userParties); // However, here 'userParties' return '[]'
this.setState({ followUsersEvents: userParties });
this.setState({ userImage: userImg });
run this code and you will see that outside will be printed first and dispatchGetUserEvents later, as I mentioned in comments dispatchGetUserEvents is async function, so first will be executed console.log('outside', ...);

Array is empty after for loop

I'm setting an array before a for loop, inside the for loop I use .push() to add data to the array but after this loop the array is empty.
MessageNotification.find({for: req.user.id}, (err, notifications) => {
var userdata = [];
notifications.forEach((notif) => {
User.findById(notif.from, (err, user) => {
userdata.push({
id: user._id,
username: user.username,
thumbnail: user.thumbnail
});
});
});
console.log(userdata);
});
As you can see on the code I am running a mongoose query to find all notifications for a specific id, then, I am setting an array to get details about the sender of each notification. Inside a forEach loop I save the results in the array. Console.log on line 12 returns an empty array [] even though User.findById on line 4 gets the User data
The problem is you are doing and asynchronous call in forEach. You should either use async/await with for..of or promises in such cases.
In your case, actually there is no need to do multiple calls on User model, you can get the desired result in a single query. Try the below code:
MessageNotification.find({
for: req.user.id
}, (err, notifications) => {
const fromArr = notifications.map(({
from
}) => from); // taking out **from** values from all notifications
User.find({
_id: {
$in: fromArr
}
}, (err, users) => { // single query to get the data
const userData = users.map(({
_id: id,
username,
thumbnail
}) => {
return {
id,
username,
thumbnail
};
});
console.log(userData);
});
});
The problem here is actually that you're calling .forEach with an async calls inside. Rather than iterating over each item in the array, and running a separate query for each, you should use the $in operator which will check if any values match items within the array, with a single query.

React's setState mutates variable

Very strange behavior, most probably a bug in my code:
I get an API response object (json) and when I setState using one of the object's properties as value, the object changes. I thought this was a problem with the backend or fetch method, but it has been proven not to be.
Code is generally as follows:
fetch(this.props.url, {
method: 'POST',
body: JSON.stringify({
class: 'property',
action: 'view',
objectId: this.props.element.id,
token: this.props.token,
}),
})
.then(response => response.json())
.then(json => {
this.setState({
property: json.property
});
console.log(json);
})
What I am supposed to get:
{
property: {
units: {
{
id: 31,
...
},
{
id: 33,
...
}
}
}
}
{
What I actually get:
property: {
units: {
{
id: 33,
...
},
{
id: 33,
...
}
}
}
}
Needless to say, response from backend is with the proper ids, which are unique.
Any ideas what I might have done wrong? This is not supposed to happen, is it? How does the json variable change?
Thanks.
Ok, found my mistake. It is very confusing and honestly, I believe this should not happen by design, but anyways:
Once I set state.property to json.property, I pass the state.property as a prop to a child element. Within that child element I am doing some filtering and mapping using props.property and at one point I've mistakenly used a single equal (=) sign instead of double (==) when comparing the ids in a filter function.
Apparently this sets the wrong id and goes all the way back to the initial json response (so, filter function -> child element props -> ?parent element state? -> json response). So, be ccareful with your filter functions, unless you want to spend a few days tracking the impossible.

How do i save my to-do app's list in local storage?

This is what I have so far: https://gist.github.com/justgoof9/f6250cdbd615bda139ef8d56375fa12c
So when I add items to the list then when I refresh the browser, I want it to still save. I want to do it with JSON but don't know how. Can anyone help me?
Yes you can achieve it by using local storage, so whenever you push something to your to Todo list, save the updated list in local storage and then when you are rendering in the UI use the data that is stored in local storage. Here is a small example to achieve this --> https://www.w3schools.com/html/html5_webstorage.asp
Hope this solved your problem.
Hi storing objects in LocalStorage is a bit tricky because LocalStorage accepts strings, but JSON.stringify() comes to the rescue! In you function addToList:
addToList = input => {
let listArray = this.state.lists;
listArray.push(input);
this.setState({
list: listArray,
userInput: ""
});
};
You want to add a LocalStorage call that saves the list from this.state into LocalStorage, like this:
addToList = input => {
let listArray = this.state.lists;
listArray.push(input);
this.setState({
lists: listArray,
userInput: ""
}, () => {
window.localStorage.setItem('savedList', JSON.stringify(this.state.lists));
});
};
And to retrieve it, you need to parse it back into an array/object, like this:
componentDidMount() {
const list = window.localStorage.getItem('savedList');
const parsedList = JSON.parse(list);
this.setState({
lists: parsedList,
})
}
Now every new item you add is saved to localStorage and is retrieved on refresh, all that is left is to apply the same logic to removing items, like this:
listOnClick = index => {
var arr = this.state.lists;
arr.splice(index, 1);
this.setState({ lists: arr }, () => {
window.localStorage.setItem('savedList', JSON.stringify(this.state.lists));
});
};
You also had a typo in addToList, you were assigning to this.state.list instead of this.state.lists

Resources