Vue.js 3.0: Read and set object properties from method - javascript

I am learning and creating a Vue application. When I try setting the properties, I get an error like this, Cannot read property 'Selected.type' of undefined
This is how I try to do it:
<script>
export default {
data() {
return {
info: {},
Selected: {
type: '',
country: '',
}
};
},
methods: {
fetchData () {
fetch(`https://data.brreg.no/enhetsregisteret/api/enheter/983609155`)
.then( resp => resp.json())
.then((data) => (this.info = data))
.then(function (data) {
console.log(data.organisasjonsform.beskrivelse);
this.Selected.type=data.organisasjonsform.beskrivelse;
})
.catch(err => console.error(err))
}
},
mounted() {
this.fetchData();
},
};
</script>
Why I am getting this error? I am new to VueJS. Can someone please help me out here?

This is because this refer to the execution context of the callback-function, not the Vue component. It is caused by using the function-keyword to declare your callback instead of the newer () => {} syntax.
If you change your code to:
fetch(`https://data.brreg.no/enhetsregisteret/api/enheter/983609155`)
.then( resp => resp.json())
.then((data) => (this.info = data))
.then((data) => {
console.log(data.organisasjonsform.beskrivelse);
this.Selected.type=data.organisasjonsform.beskrivelse;
})
It should work.
An alternative syntax, is to capture the this context in a variable within the closure of your fetchData-method
fetchData () {
const self = this;
fetch(`https://data.brreg.no/enhetsregisteret/api/enheter/983609155`)
.then( resp => resp.json())
.then((data) => (this.info = data))
.then(function (data) {
console.log(data.organisasjonsform.beskrivelse);
self.Selected.type=data.organisasjonsform.beskrivelse;
})
.catch(err => console.error(err))
}

This should work, I didn't try it but it's obvious.
you have to add the 'this' before Selected.type to access it.
Edit:
My bad, I totally forgot about the function context. That's what happens when you don't run your code before posting, i guess.
fetch(`https://data.brreg.no/enhetsregisteret/api/enheter/983609155`)
.then( resp => resp.json())
.then((data) => (this.info = data))
.then((data) => {
console.log(data.organisasjonsform.beskrivelse);
this.Selected.type=data.organisasjonsform.beskrivelse;
})
.catch(err => console.error(err))
}

Related

Cannot read property 'then' of undefined for axios wrapper

I have a bit of a similar issue like this but I can't seem to get it right. I know I have to return a promise and I think I do, although it's still not accepted. Here is my wrapper function for axios calls:
export const callGraph = (url, token) => {
return axios.get(url, {headers: { Authorization: `Bearer ${token}` }})
}
This is the function that invokes callGraph that in turn should return a Promise:
export const getGraphProfile = () => {
if (auth.getAccount()) {
auth.getToken(loginRequest)
.then(response => {
return callGraph(graphConfig.graphMeUrl, response.accessToken)
})
.catch(error => { console.log(error) })
}
}
As you can see I explicitly request return callGraph so I can use it like this:
getGraphProfile()
.then(response => { console.log('givenName ', response.data.givenName) })
.catch(error => console.log(error))
For one reason or another I'm still missing something. Thank you for your help.
You should return the axios promise
export const getGraphProfile = () => {
if (auth.getAccount()) {
return auth.getToken(loginRequest)
.then(response => {
return callGraph(graphConfig.graphMeUrl, response.accessToken)
})
.catch(error => { console.log(error) })
}
}

Save API data into an array with vue.js

I need help doing this. I want to save the user list from the API to an array (called "name"). How can I do this? I tried this forEach but can't make it work. Thanks!
Edit: I wraped the function, still not working.
import axios from 'axios'
export default {
data () {
return {
info: null,
name: []
}
},
mounted () {
axios
.get('http://localhost:3000/api/users/', {mode: 'no-cors'})
.then(response => (this.info = response.data))
.then(() => info.data.forEach(element => {
}))
.catch(error => {
console.log(error)
this.errored = true
})
.finally(this.loading = false)
}
}
From the code above I'm assuming the data in this.info in correct. The problems I see in your code are:
1.
.then(response => (this.info = response.data))
.then(() => info.data.forEach(element => {
}))
info looks to be undefined. I assume this should be this.info.
.then(response => (this.info = response.data))
.then(() => this.info.data.forEach(element => {
}))
Or if you're using the arrow function syntax and returning an assignment expression, you can use
.then(response => (this.info = response.data))
.then(info => info.data.forEach(element => {
}))
Which I don't really recommend, since some linting rules disallow returning assignment expressions (for good reasons). To chain a promise that relies on this implicit language behavior can make code less easily understood.
2.
What forEach does matters. Vue's reactivity does not pick up certain assignment syntax, i.e. this.name[i] = element. You can use array methods like push, but I recommend you use functional programming operators, like map and filter:
.then(() => (this.name = this.info.data.map(element => {
})))
Maybe the this reference is not correct, because on callback methods is on another context, try it:
export default {
data () {
return {
info: null,
name: []
}
},
mounted () {
var self = this
axios
.get('http://localhost:3000/api/users/', {mode: 'no-cors'})
.then(response => (self.info = response.data))
.then(info.data.forEach(element => {
});)
.catch(error => {
console.log(error)
this.errored = true
})
.finally(this.loading = false)
}
}
you forgot to encapsulate the callback into a function receiving the info variable,
try this:
import axios from 'axios'
export default {
data () {
return {
info: null,
name: []
}
},
mounted () {
axios
.get('http://localhost:3000/api/users/', {mode: 'no-cors'})
.then((response) => response.data.forEach(element => {
}))
.catch(error => {
console.log(error)
this.errored = true
})
.finally(this.loading = false)
}
}

How to fetch data from multiple db from the node.js in frontend react.js

I have the below code, where I have to get data from all the files in the same DB. Node.js is running at the backend. When I try the below code, I always get the last fetch, can anyone please help me how to fix this.
The below is from the react JS frontend.
componentDidMount() {
console.log("This Worked Sucessfully")
this.getDataFromDb();
if (!this.state.intervalIsSet) {
let interval = setInterval(this.getDataFromDb, 1000);
this.setState({ intervalIsSet: interval });
}
}
getDataFromDb = () => {fetch('http://172.24.78.202:3001/api/passed')
.then(data => data.json())
.then(res => this.setState({ passed: res.data }));
};
getDataFromDb = () => {fetch('http://172.24.78.202:3001/api/failed')
.then(data => data.json())
.then(res => this.setState({ failed: res.data }));
};
getDataFromDb = () => {fetch('http://172.24.78.202:3001/api/all')
.then(data => data.json())
.then(res => this.setState({ data2: res.data }));
};
render() {
const primaryColor = getColor('primary');
const secondaryColor = getColor('secondary');
const { passed, failed, data2 } = this.state
From what I see by your code, you seem to be re-writing your goGetDataFromDB two times. Try changing the names of each function or, the way you call them. You can also take advantage of Promise.all to group the results of each call into a single return handle.
Check this link for the documentation of Promise.all
You could refactor your current code to something like this:
class MyComponent extends React.Component {
componentDidMount() {
this.getDataFromDb();
if (!this.state.intervalIsSet) {
let interval = setInterval(this.getDataFromDb, 1000)
this.setState({intervalIsSet: true })
}
}
getDataFromDb = () => {
Promise.all([
'http://172.24.78.202:3001/api/passed',
'http://172.24.78.202:3001/api/failed',
'http://172.24.78.202:3001/api/all'
].map(url => (
fetch(url)
.then(data => data.json())
.then(res => res.data)
)
)).then(([passed, failed, data2]) =>
this.setState({ passed, failed, data2 })
);
}
render() {
//...
}
}
I tried to keep as much as your code as possible so you could notice the differences.
I hope this helps.

How to setState after a loop of async functions

The closest answer I could find was this, which didn't help since I need to setState: How do I run a function after using array.map?
I think the answer should be simple, but I'm pretty new to Javascript. I'm trying to move the setState for isLoading to AFTER I've pulled all of the profiles.
componentDidMount() {
console.log('MatchesScreen init props: ', Object.keys(this.props))
Object.keys(this.props.profile.profile.matches).map((username) => {
console.log('match', username)
url = 'https://xxxxxxx.execute-api.us-west-2.amazonaws.com/prod/profile?username=' + username
fetch(url, {
method: 'GET',
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
})
this.props.addMatch(responseJson)
})
.catch((error) =>{
console.error(error);
})
})
}
I've tried various things like appending a .then() to the map function, but so far no luck.
You could return each promise inside the .map() function, which would leave you with an array of promises. Once you have that, you can use Promise.all() to wait for all the promises in the array to resolve.
componentDidMount() {
console.log('MatchesScreen init props: ', Object.keys(this.props))
// Put all promises into an array
const promisesArray = Object.keys(this.props.profile.profile.matches).map((username) => {
console.log('match', username)
url = 'https://xxxxxxx.execute-api.us-west-2.amazonaws.com/prod/profile?username=' + username;
// Return each promise
return fetch(url, {
method: 'GET',
})
.then((response) => response.json())
.then((responseJson) => {
this.props.addMatch(responseJson)
})
.catch((error) =>{
console.error(error);
});
});
// Wait for all promises in array to resolve
Promise.all(promisesArray)
.then(() => {
// This will execute once all promises have resolved
this.setState({
isLoading: false,
});
})
.catch(e => console.error(e));
}
Try using the async/await pattern as follows:
async componentDidMount() {
...
Object.keys(this.props.profile.profile.matches).map((username) => {
...
await fetch(url, {
...
then move your setState method into its own callback, which you can call in your .then() statements following your fetch.
I like this reference: https://alligator.io/js/async-functions/
Try wrapping the Object.keys() in a while loop with an if statement at the end.
var profilesMatched = 0;
while(profilesMatched < Object.keys(this.props.profile.profile.matches).length){
Object.keys(this.props.profile.profile.matches).map((username) => {
console.log('match', username)
url = 'https://xxxxxxx.execute-api.us-west-2.amazonaws.com/prod/profile?username=' + username
fetch(url, { method: 'GET', })
.then((response) => {response.json()})
.then((responseJson) => {
this.props.addMatch(responseJson);
profilesMatched++;
})
.catch((error) => {
console.error(error);
});
});
if(profilesMatched == Object.keys(this.props.profile.profile.matches).length){
this.setState({
isLoading: false,
})
}
}

Fetch returns undefined when imported

I have a function that fetches data from the url and is supposed to return it:
const fetchTableData = () => {
fetch('https://api.myjson.com/bins/15psn9')
.then(result => result.json())
.then(data => {
return data;
})
}
export default fetchTableData;
The problem is that when i import this function and try to use it, it always returns undefined.
When i console log the data inside the function itself, you can see it is available. The function just doesn't work when i try to import it.
What is the problem here? Why does it work that way?
Try this =) You have to return something from the fetchTableData function also.
const fetchTableData = () => {
const fetchedData = fetch('https://api.myjson.com/bins/15psn9')
.then(result => result.json())
.then(data => {
return data;
})
return fetchedData;
}
export default fetchTableData;
Or you can just return it like this:
const fetchTableData = () => {
return fetch('https://api.myjson.com/bins/15psn9')
.then(result => result.json())
.then(data => {
return data;
})
}
export default fetchTableData;
In your code you were not returning from the fetchTableData function. Only from the the second then() callback. When a function has no return value, undefined will be returned.
Try this instead:
const fetchTableData = () => {
const myResponse = fetch('https://api.myjson.com/bins/15psn9')
.then(result => result.json())
.then(data => {
return data;
})
return myResponse;
}
export default fetchTableData;
What now happens is the following:
The response return by the second then() function is returning the data.
We are saving this data in a variable, named myResponse.
We are now returning this value from the function fetchTableData.
You need to either store data in a global variable or assign any variable to fetch to get return data.
//First way
fetch('https://api.myjson.com/bins/15psn9')
.then(result => result.json())
.then(data => {
console.log("data",data);
});
//Second way
let binData = null;
fetch('https://api.myjson.com/bins/15psn9')
.then(result => result.json())
.then(data => {
binData = data;
console.log("binData", binData);
});
Here is the working example.

Categories