VueJS data from nested Axios requests not rendering in view - vue.js

I am trying to list a set of posts from an API on a page using VueJS and Axios. The issue I am facing is one piece of the data (the post url) needs to be retrieved with a separate API call for that specific post and they provide the url for that data in the initial API call. I have the first part working perfectly, but I can't get the href to render in the view when the value is showing up in the Vue devtools.
JS
const vm = new Vue({
el: '#app',
data: {
posts: []
},
mounted() {
this.getPosts();
},
methods: {
getPosts() {
axios.get("api_url")
.then((response) => {
this.posts = response.data.posts;
// Get URL for each post from separate API call
this.posts.map(post => {
axios.get(post.details_url+"&output=json")
.then((response) => {
post.official_url = response.data.post.pet_details_url;
}).catch( error => { console.log(error); });
});
}).catch( error => { console.log(error); });
}
}
});
HTML
<div id="app">
<div v-for="post in posts">
<a :href="post.official_url"> //href won't render
<h2>{{ post.title }}</h2>
<p>{{ post.text }}</p>
</a>
</div>
</div>
Data showing up in Vue DevTools

It might be reactive problem. You can try Vue.set
getPosts() {
let vm = this
axios.get("api_url")
.then((response) => {
this.posts = response.data.posts;
// Get URL for each post from separate API call
this.posts.map((post, index) => {
axios.get(post.details_url+"&output=json")
.then((response) => {
post.official_url = response.data.post.pet_details_url;
Vue.set(vm.posts, index, JSON.parse(JSON.stringify(post)))
}).catch( error => { console.log(error); });
});
}).catch( error => { console.log(error); });
}

Related

Vue.js Composition API vs Options API - posts ref in a v-for loop

I'm still new to VueJS, and I cannot figure this one out.
I have a page that loads with axios from wordpress my posts:
export default {
data() {
return {
postsUrl: "https://localhost/wordpress/wp-json/wp/v2/news",
posts: [] as any[],
isLoading: false,
regex: /(<([^>]+)>)/gi,
errorCaught: false,
};
},
methods: {
getPosts() {
this.isLoading = true;
axios
.get(this.postsUrl, { params: { _embed: true } })
.then((response) => {
this.posts = response.data;
console.log("Pages retrieved!");
console.log(this.posts);
this.isLoading = false;
})
.catch((error) => {
console.log(error);
if (error) {
this.isLoading = false;
setTimeout(() => {
this.errorCaught = true;
}, 1100);
}
});
},
},
mounted() {
this.getPosts();
},
};
and the template
<template>
<div class="news-container">
<div class="loading">
<transition name="fadeLoading">
<div v-if="isLoading">Loading...</div>
</transition>
<transition name="fadeLoading">
<div v-if="errorCaught">There was an error loading news</div>
</transition>
</div>
<ul v-for="(index) in posts" :key="index" ref="posts">
<h1>
<router-link :to="index.slug" tag="div" key="page.id"
>{{ index.title.rendered }}
</router-link>
</h1>
<img
v-if="index._embedded['wp:featuredmedia']"
:src="index._embedded['wp:featuredmedia'][0].source_url"
/>
<p class="date">{{ index.date }}</p>
</ul>
</div>
</template>
This works fine, no problem with the Options API.
But when I want to convert this to the Composition API, the posts don't appear:
<script setup lang="ts">
import axios from "axios";
import { ref } from "vue";
import { onMounted } from "vue";
const postsUrl = "https://localhost/wordpress/wp-json/wp/v2/news";
var posts = ref([] as any);
const isLoading = ref(false);
const regex = /(<([^>]+)>)/gi;
const errorCaught = ref(false);
const getPosts = () => {
isLoading.value = true;
axios
.get(postsUrl, { params: { _embed: true, page: 1 } })
.then((response) => {
posts = response.data;
console.log("Pages retrieved!");
console.log(posts);
isLoading.value = false;
})
.catch((error) => {
console.log(error);
if (error) {
errorCaught.value = true;
}
});
};
onMounted(() => {
getPosts();
});
</script>
I suspect there is a misunderstanding on my part how refs work, because If I edit the <template> (and have npm run dev running the server), I can see that the posts appear.
Could you help me with what am I doing wrong and why?
Thank you for your time
Your mistake is here
posts = response.data;
When you use ref you have to use it with value. Change your code to this:
posts.value = response.data;
It should be working fine. For more detail you should check here:
https://vuejs.org/api/reactivity-core.html#ref

how to for loop data from localStorage nuxtjs

this my code previously
<ul>
<li v-for="item in data.data">{{ item.name }}</li>
</ul>
export default {
layout: 'main',
async asyncData({ $axios }) {
const data = await $axios.$get('XXXXXXXXXXXXXXXXXXXXX');
return { data };
}
}
this can work but when i change the page and turnback to this page
axios send request again i need one time request and save data response to cache (localStorage)
now i try this code
export default {
layout: 'main',
mounted() {
this.starter()
},
methods: {
starter() {
let room = JSON.parse(localStorage.getItem('game_room'))
if (!room) {
fetch('XXXXXXXXXXXXXXXXXXXXX')
.then(res => res.json())
.then(json => {
localStorage.setItem('game_room', JSON.stringify(json))
let room = JSON.parse(localStorage.getItem('game_room'));
console.log('Response ', room.data[0].title)
});
} else {
console.log('Caching ', room.data[0].title)
}
}
}
}
now this response data save to localStorage but i dont know how to use data to v-for like the my code previously

How to handle the axios errors in the context of Vuejs

I want to display/print 'Disabled' when ever my API returns any error and display 'Enabled' when it is returning successfully with 200 ok status.
Here's what my API is returning:
So, my API is returning error currently, so i want to print/display 'Disabled'.
Here how i did it:
<template>
<div class="api_data">
<span class="trick_not_ok" v-if="error" >{{error}}</span>
<span class="trick_ok" v-if="noerror" >{{noerror}}</span>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: Api_data,
data () {
return {
error: [],
noerror: []
}
},
created() {
axios.get('...URL...')
.then((response) => {
console.log(response.data)
this.noerror = 'Enabled'
})
.catch((error) => {
if (error) {
console.log(error)
this.error = 'Disabled'
}
})
}
}
</script>
But nothing is printed/displayed on my screen, and i am getting error in my console as GET ...URL... 401 (UNAUTHORIZED), How do i display 'Disabled' when my API returns error and 'Enabled' when my API is returning successfully.
Note: I have also tried in .catch as if (error.response.stastus) and if (error.status) but both did not work and i am getting the same error in my console.
Someone please do help me with this.
Here
is a codepen solution that I'd use for your trouble. Using boolean for selecting the status and then string for the message you want to display.
new Vue({
el: "#app",
data () {
return {
isError: false,
noerror: false,
message:'loading'
}
},
created() {
axios.get('...URL...')
.then((response) => {
console.log(response.data)
this.noerror = true
this.message = 'enabled'
})
.catch((error) => {
if (error) {
console.log(error)
this.isError = true
this.message = 'disabled'
}
})
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
<div id="app">
<div class="api_data">
<span class="trick_not_ok" v-if="isError">{{message}}</span>
<span class="trick_ok" v-if="noerror">{{message}}</span>
</div>
</div>
you need to the code to understand what this status is,
switch(status) { case 401: message = 'UNAUTHORIZED'; break ...}
or from api you send a json for error message and return by error.response.data.message for this json:
{"message": "UNAUTHORIZED"}
Your code seems ok. Here is the working demo.
new Vue({
el: "#api_data",
data() {
return {
error: null,
noerror: null
}
},
mounted() {
axios.get('https://api.bonsai.io/clusters')
.then((response) => {
console.log(response.data)
this.noerror = 'Enabled'
})
.catch((error) => {
if (error) {
this.error = 'Disabled'
}
})
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
<div id="api_data">
<span class="trick_not_ok" v-if="error">{{error}}</span>
<span class="trick_ok" v-if="noerror">{{noerror}}</span>
</div>

Cannot set property after Get reques - Axios and HTML5 datalist

I am trying to do a GET request using Axios , but get the following error in console:
TypeError: Cannot set property 'films' of undefined
at eval (SearchBar.vue?e266:26)
SearchBar.vue
<template>
<section>
<input v-model='film' type='text' list='films'>
<datalist id='films'>
<option v-for='film in films' :key='film.episode_id'>{{film}}</option>
</datalist>
</section>
</template>
<script>
import axios from "axios";
export default {
name: "SearchBar",
data() {
return {
film: "",
films: []
};
},
created() {
axios
.get("https://swapi.co/api/films/")
.then(function(response) {
// handle success
//console.log(response);
this.films = response.data.results;
})
.catch(function(error) {
// handle error
console.log(error);
});
}
};
</script>
Anyone can tell me why I get the error? Note: I am running this locally for instant prototyping via Vue-Cli
One way is to use Arrow function:
created() {
axios
.get("https://swapi.co/api/films/")
.then((response) => {
// handle success
//console.log(response);
this.films = response.data.results;
})
.catch(function(error) {
// handle error
console.log(error);
});
}
2. Another way that = this & then use that inside promise callback
created() {
const that = this; // <-- assign this in that
axios
.get("https://swapi.co/api/films/")
.then(function (response) {
// handle success
//console.log(response);
that.films = response.data.results;
})
.catch(function(error) {
// handle error
console.log(error);
});
}

Nuxt.js and handle API 404 response for dynamic pages

I use Nuxt.js and I have dynamic page /items/{id}:
<template>
<div>
<h1>Item #{{ item.id }} «{{ item.title }}»</h1>
</div>
</template>
<script>
import { api } from '../../mo/api'
export default {
asyncData({ params }) {
return api(`items/${params.id}`)
},
}
</script>
Backend API returns object {item: {id: .., title: "...", ...}}.
But if an item with specified ID not exist API returns 404 response.
And Vue crash with "[Vue warn]: Property or method "item" is not defined on the instance but referenced during render."
How can I handle 404 response?
My api.js module:
import axios from 'axios'
export function api(url) {
url = encodeURIComponent(url)
return axios
.get(`http://localhost:4444/?url=${url}`)
.then(({ data }) => {
return data
})
.catch((err) => {
// 404 catch there
})
}
Solution:
Need to read manual: https://nuxtjs.org/guide/async-data/#handling-errors
just execute error function :)
<script>
export default {
asyncData({ params, error }) {
return axios
.get(`https://my-api/posts/${params.id}`)
.then((res) => {
return { title: res.data.title }
})
.catch((e) => {
error({ statusCode: 404, message: 'Post not found' })
})
},
}
</script>
If you're using the fetch() hook, this is how it should be written
<script>
export default {
async fetch() {
try {
await fetch('https://non-existent-website.commmm')
.then((response) => response.json())
} catch (error) {
this.$nuxt.context.error({
status: 500,
message: 'Something bad happened',
})
}
},
}
</script>
More context available here: https://nuxtjs.org/announcements/understanding-how-fetch-works-in-nuxt-2-12/#error-handling
Need to read the manual: https://nuxtjs.org/guide/async-data/#handling-errors :) .