Reputation: 2418
I'm successfully getting data into the console. When I try to print that data to the page by calling the method in double moustache braces it doesn't appear on screen. All other data in template appears just fine.
Template:
<template>
<div>
<div v-for="data in imageData" :key="data.id">
<div class="card">
<img :src="data.source" :alt="data.caption" class="card-img" />
<div class="text-box">
<p>{{ moment(data.timestamp.toDate()).format("MMM Do YYYY") }}</p>
<p>{{ data.caption }}</p>
// The Geocoding method is the problem
<p>{{reverseGeocode(data.location.df, data.location.wf)}}</p>
</div>
</div>
</div>
</div>
</template>
Method:
methods: {
reverseGeocode: (lat, long) => {
fetch(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${long}&key=API_KEY&result_type=locality`
).then((res) =>
res.json().then((data) => {
console.log(data.results[0].formatted_address); // works fine
return data.results[0].formatted_address;
})
);
},
},
Here's the image data I'm getting in props
Upvotes: 2
Views: 1124
Reputation: 1763
You should change your approach to the following:
Do all requests in the created() lifecycle method and store the results in a data attribute then iterate over the data attribute. The created()
lifecycle method executes before the DOM is mounted so all data fetching APIs should be called there. FYR: https://v2.vuejs.org/v2/guide/instance.html
Please also refer to Vue.js - Which component lifecycle should be used for fetching data?
Upvotes: 0
Reputation: 176
The above I think is correct as well, but I would push for async
async reverseGeocode(lat, long) {
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${long}&key=API_KEY&result_type=locality`
);
const data = response.json();
return data.results[0].formatted_address;
}
Upvotes: 0
Reputation: 333
Your problem is a common problem when you start making requests in JavaScript.
The date requests are asynchronous so the method cannot return a value after the execution of the method has finished.
Imagine the following call stack:
You are trying to do a return in step 4 and it should be in 3.
To solve this you should use async with await. You could also solve it by making a component and passing the data (this is my favorite since you are using vue).
Component parent
<template>
<div>
<component-card v-for="data in imageData" :key="data.id" :dataItem="data">
</component-card>
</div>
</template>
Child component
<template>
<div class="card">
<img :src="dataItem.source" :alt="dataItem.caption" class="card-img" />
<div class="text-box">
<p>{{ moment(dataItem.timestamp.toDate()).format("MMM Do YYYY") }}</p>
<p>{{ dataItem.caption }}</p>
<p>{{formattedAddress}}</p>
</div>
</div>
</template>
<script>
export default {
props: {
dataItem: {
type: {},
default: () => ({})
}
},
data() {
return {
formattedAddress: ""
};
},
created() {
this.reverseGeocode(this.dataItem.location.df, dataItem.location.wf)
},
methods: {
reverseGeocode(lat, long) {
fetch(
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${long}&key=API_KEY&result_type=locality`
).then(res =>
res.json().then(data => {
console.log(data.results[0].formatted_address); // works fine
this.formattedAddress = data.results[0].formatted_address;
})
);
}
}
};
</script>
I have not tried it, surely some things are missing but the template should be that.
Upvotes: 1