Loading component after fetch in vuejs - api

I'm trying to consume an API using axios.
This is my code untill now
<select>
<option v-for="value in values"> value.name </option>
</select>
// js
data(){
values: [],
},
created() {
this.getData();
},
methods: {
getData: () => {
axios.get('url')
.then(res => {
this.value = res.data.dados;
console.log(res.data.dados);
})
.catch(error => {
console.log(error);
});
}
}
The promise's console.log is working normally, but the options with data isn't rendered.
It's probably because my select component is being rendered before the 'getData()'. How can I fix it?

Just put a loading handler.
<select v-if="loaded">
<option v-for="value in values"> value.name </option>
</select>
// js
data(){
values: [],
loaded: false,
},
created() {
this.getData();
},
methods: {
getData: () => {
axios.get('url')
.then(res => {
this.value = res.data.dados;
this.loaded = true;
})
.catch(error => {
console.log(error);
this.loaded = true;
});
}
}

You've a typo on this.value, it should be this.values. If that doesn't work, use this.$forceUpdate() to force re-render component
<select>
<option v-for="value in values">{{ value.name }}</option>
</select>
// js
data(){
values: [],
},
created() {
this.getData();
},
methods: {
getData: () => {
axios.get('url')
.then(res => {
this.values = res.data.dados; // change value to values
console.log(res.data.dados);
this.$forceUpdate(); // add forceUpdate
})
.catch(error => {
console.log(error);
});
}
}

Related

Live Search Component

I am fetching my data from external API link and I would like to filter them - live searching, so when I type a letter, the results that includes that letter will get filtered.
For now I am not able to do it and when I click into my input I just get all the results printed out and nothing is happening when I am trying to filter them.
This is my logic in script:
data() {
return {
result: "",
modal: false,
results: [],
filteredResults: [],
};
},
mounted() {
axios
.get("secretDataURL")
.then((response) => {
this.filteredResults = response.data;
})
.catch((error) => (this.filteredResults = console.log(error)))
.finally(() => console.log("Data successfully loaded"));
},
methods: {
filterResults() {
if (this.result.lenght == 0) {
this.filteredResults = this.results;
}
this.filteredResults = this.results.filter((result) => {
return result.toLowerCase().startsWith(this.result.toLowerCase());
});
},
setResult(result) {
this.result = result;
this.modal = false;
},
},
watch: {
state() {
this.filterResults();
},
}
And my template
<div #click="modal = false"></div>
<input
type="text"
v-model="result"
autocomplete="off"
#input="filterResults"
#focus="modal = true"
/>
<div v-if="filteredResults && modal">
<ul>
<li
v-for="(filteredResult, index) in filteredResults"
:key="index"
#click="setResult(filteredResult)"
>
{{ filteredResult.name }}
</li>
</ul>
</div>
How can I make it work, where my logic is failing ?
U get the data in hook mounted.
And then lost it.
Change this.filteredResults = response.data; to this.results = response.data;

VueJs, call a method from concatenated element

I would like to call a method from a concatenated checkbox.
here is my code:
methods: {
listServices(serviceId) {
axios
.get(
process.env.ROOT_API + "Service/List?Id=" + serviceId,
this.$store.getters.getTokenHeaderFormData
)
.then(response => {
response.data.forEach(el => {
this.dataset.push([
el.serviceName,
`<input type="checkbox"
onchange="${this.updateService(el.ServiceId)}">` // <-- Call UpdateService method
]);
});
})
.catch(error => {
console.log(error);
});
},
updateService(serviceId){
console.log(serviceId);
},
The onchange="${this.updateService(el.ServiceId)}" does not work. how can I do this?
The proper way to do this is to use v-for:
<template>
<ul>
<li v-for="item in dataset" :key="item[1]">
<input type="checkbox" #change="updateService(item[1])">
</li>
</ul>
</template>
<script>
export default
{
methods:
{
listServices(serviceId)
{
axios.get(
process.env.ROOT_API + "Service/List?Id=" + serviceId,
this.$store.getters.getTokenHeaderFormData
).then(response =>
{
response.data.forEach(el =>
{
this.dataset.push([
el.serviceName,
el.ServiceId
]);
});
}).catch(error =>
{
console.log(error);
});
},
updateService(serviceId)
{
console.log(serviceId);
},
}
}
</script>

Using HTML datalist element with VueJS? Can't use hyperlinks?

I am trying to use HTML's datalist [https://www.w3schools.com/tags/tag_datalist.asp] element rather than an autocompletion library. I tried to wrap an a href element around the post.title.
Unfortunately, it looks like this is not possible with the datalist's option element?
Here's my template:
<input v-model='post' type='text' list='posts'>
<datalist id='posts'>
<option v-for='post in posts' :key='post.id'>
<a :href='url + `${post.id}`'>{{post.title}}</a>
</option>
</datalist>
Script:
import axios from "axios";
export default {
name: "SearchBar",
data() {
return {
post: "",
posts: [],
url: "https://jsonplaceholder.typicode.com/posts/",
//placeholder: "Search or jump to item"
};
},
created() {
this.getPosts();
},
methods: {
getPosts() {
axios
.get("https://jsonplaceholder.typicode.com/posts")
.then(response => {
console.log(response);
this.posts = response.data;
})
.catch(error => {
console.log(error);
});
}
}
};
Anyone got some workarounds for this? Thank you
friend.
if you want to check.
regards!
Here's a link!
new Vue({
el: "#app",
data() {
return {
posts: []
}
},
created() {
this.getPosts()
},
methods: {
getPosts() {
axios
.get("https://jsonplaceholder.typicode.com/posts")
.then(response => {
console.log(response);
this.posts = response.data;
})
.catch(error => {
console.log(error);
});
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input list="posts" name="posts">
<datalist id="posts">
<option v-for="post in posts" :key="post.id" :value="post.title">
{{ post.title }}
</option>
</datalist>
</div>

How to bind data from an api function into data object in vue.js

I am performing a Axios.get() to a Weather API, in result i want to filter specific data of information about "current weather" etc.
<template lang="html">
<div id="weather">
{{weatherData}}
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
weatherData: {
stringSummary: this.weatherApi.data.currently.summary,
},
};
},
created() {
this.weatherApi();
},
methods: {
async weatherApi() {
axios.get('https://api.darksky.net/forecast/
89cef1a2abe989e0d09a4ebd75f02452/53.551085,-9.993682?
lang=de&units=si')
.then((response) => {
console.log(response);
return response;
})
.catch((error) => {
console.log(error);
});
},
},
};
</script>
Please check my "stringSummary" part inside Data. Shouldn't this work?
I am thankful for any help.
You should assign weatherData in then block:
methods: {
async weatherApi() {
axios.get('https://api.darksky.net/forecast/
89cef1a2abe989e0d09a4ebd75f02452/53.551085,-9.993682?
lang=de&units=si')
.then((response) => {
this.weatherData = {
stringSummary: response.data.currently.summary
}
return response;
})
.catch((error) => {
console.log(error);
});
},

Computed property "main_image" was assigned to but it has no setter

How can I fix this error "Computed property "main_image" was assigned to but it has no setter"?
I'm trying to switch main_image every 5s (random). This is my code, check created method and setInterval.
<template>
<div class="main-image">
<img v-bind:src="main_image">
</div>
<div class="image-list>
<div v-for="img in images" class="item"><img src="img.image"></div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Item',
data () {
return {
item: [],
images: [],
}
},
methods: {
fetchImages() {
axios.get(`/api/item/${this.$route.params.id}/${this.$route.params.attribute}/images/`)
.then(response => {
this.images = response.data
})
.catch(e => {
this.images = []
this.errors.push(e)
})
},
},
computed: {
main_image() {
if (typeof this.item[this.$route.params.attribute] !== 'undefined') {
return this.item[this.$route.params.attribute].image_url
}
},
},
watch: {
'$route' (to, from) {
this.fetchImages()
}
},
created () {
axios.get(`/api/item/${this.$route.params.id}/`)
.then(response => {
this.item = response.data
})
.catch(e => {
this.errors.push(e)
})
this.fetchImages();
self = this
setInterval(function(){
self.main_image = self.images[Math.floor(Math.random()*self.images.length)].image;
}, 5000);
},
}
</script>
Looks like you want the following to happen...
main_image is initially null / undefined
After the request to /api/item/${this.$route.params.id}/ completes, it should be this.item[this.$route.params.attribute].image_url (if it exists)
After the request to /api/item/${this.$route.params.id}/${this.$route.params.attribute}/images/ completes, it should randomly pick one of the response images every 5 seconds.
I'd forget about using a computed property as that is clearly not what you want. Instead, try this
data() {
return {
item: [],
images: [],
main_image: '',
intervalId: null
}
},
methods: {
fetchImages() {
return axios.get(...)...
}
},
created () {
axios.get(`/api/item/${this.$route.params.id}/`).then(res => {
this.item = res.data
this.main_image = this.item[this.$route.params.attribute] && this.item[this.$route.params.attribute].image_url
this.fetchImages().then(() => {
this.intervalId = setInterval(() => {
this.main_image = this.images[Math.floor(Math.random()*this.images.length)].image;
})
})
}).catch(...)
},
beforeDestroy () {
clearInterval(this.intervalId) // very important
}
You have to add setter and getter for your computed proterty.
computed: {
main_image: {
get() {
return typeof this.item[this.$route.params.attribute] !== 'undefined' && this.item[this.$route.params.attribute].image_url
},
set(newValue) {
return newValue;
},
},
},