Then I reload page v-if(with computed data) not work - vue.js

im search on everywhere information about my questions - not help me.
I would like to solve this issue using v-if (not v-show)
I get orders data from Vuex store
all code work ,then page loaded and mounted and then I click other tabs and going back to current tab
code not work then I reload page on current tab
code work then I reload page on current tab , but without all v-if
I would like to solve without using third-party plugins if possible
<template>
<div class="w-full">
<!--show message div-->
<div v-if="orders.length===0" class="flex flex-wrap">
...
</div>
<!--show table div-->
<div v-if="orders.length!==0" class="flex flex-wrap">
...
</div>
</div>
</template>
computed data
computed: {
orders() {
return this.$store.state.dataList.orders
}
}
// in console.log i get 4 my orders objects (4) [{…}, {…}, {…}, {…}, ob: Observer]
actions:
fetchORDERS ({ commit }) {
return new Promise((resolve, reject) => {
axios.get('/api/data-list/orders')
.then((response) => {
commit('SET_ORDERS', response.data)
resolve(response)
})
.catch((error) => { reject(error) })
})
}
mutation:
SET_ORDERS (state, order) {
state. orders = order
}
one of the forums they wrote that the matter is in mutation, but I cannot understand what exactly and where is the error, pls help

Your basic setup is correct. That v-if should work if the data-flow is correct.
From what you're giving us, I see the following:
In your computed property you're looking at: this.$store.state.dataList.orders
In your mutation you're changing state. orders. This should be state.dataList.orders.
In other words: you should check whether the state has the shape you expect it to have. You can do this with a console.log in the computed property, or one in the mutation.

Related

looping through variable from rest api and ading it to a v-list

I am having some difficulties with the vue.js. The main problem is that I am getting this error :
Property or method `response` is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for `class-based` components, by initializing the property.
My main idea is to loop through the response (which is just an array) and add it to my v-list to have it in shape of something like this :
Instead of having create, read etc. to have my elements of array, and I am wondering how to even start with this problem.
like this is the part with my list in vue.js, I know that I think I need to use v-for method but I cant even start it without solving the error.
<v-list-group>
<v-list-item #click="getHosts()">
{{response}}
</v-list-item>
<v-list-item-group>
</v-list-item-group>
</v-list-group>
</v-list>
and this is the function that gets the array.
getHosts(){
axios.get('http://127.0.0.1:8000/something')
.then((response)=>{
console.log(response.data)
return response
})
}
I've added this function in export default in section methods, I've read about other sections and thought maybe beforeMount but I still got an error.
Thanks for any clues/help/solutions!
Instead of returning the response directly. You can bind the response in the data property.
Working Demo (For demo purpose I am using v-for instead of v-list) :
var vm = new Vue({
el: '#vue-instance',
data() {
return {
hostList: []
}
},
methods: {
getHosts() {
axios.get("https://jsonplaceholder.typicode.com/users").then(response => {
this.hostList = response.data;
}).catch((error) => {
console.warn('API error');
});
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="vue-instance">
<button v-on:click="getHosts">Get Hosts!</button>
<ul>
<li v-for="host in hostList">
{{ host.name }}
</li>
</ul>
</div>

How do i call the API once and how do i fetch different content from the same API in the context of Vuejs

I am new to Vuejs, i am calling different API's in order to fetch the contents, the different API's are same but differs in endpoint.
Here s how i did it:
<template>
<div class="body">
<div class="First content">
{{data1}}
</div>
<div class="Second content">
{{data2}}
</div>
</div>
</template>
<script>
export default {
data () {
return {
data1: [],
data2: []
}
},
created () {
this.$http.get('/serverdata/3')
.then((response) => { this.data1 = response.data })
.catch((error) => { console.log(error) })
this.$http.get('/serverdata/4')
.then((response) => { this.data2 = response.data })
.catch((error) => { console.log(error) })
}
}
</script>
My question is, how i can have only one API instead of having two. My API is: /serverdata/(only ID is changing). I know that props can be used, but i want to know how it is used within the Vue component and reuse any variable.
If suppose only one API is used as /server/ + id, i want to know how to specify the id in template in order to display the content of the particular id.
Please do help me with this small doubt because i dint find any useful information in the web. Please send me the modified code or example to understand better.
If you have multiple calls to the same endpoint and only the id changes, you can write a method which takes in the id and the prop where it needs to place the result, like this:
new Vue({
el: '#app',
data () => ({
data1: [],
data2: []
}),
created () {
[ // add your calls to this array...
[3, 'data1'],
[4, 'data2']
].forEach(payload => this.fetchData(...payload));
},
methods: {
fetchData(id, prop) {
this.$http.get(`serverdata/${id}`)
.then( r => this[prop] = r.data)
.catch(err => console.log(err));
}
}
})
<template>
<div class="body">
<div class="First content">
{{data1}}
</div>
<div class="Second content">
{{data2}}
</div>
</div>
</template>
Depending on how similar the responses are, you might be able to streamline the template code (perhaps use a v-for). But that's a speculation. You've given no context so far.
You can go further and also remove the data prefix in the model properties (assuming all props are prefixed with data), changing it to:
[[3, 1], [4, 2]].forEach(payload => this.fetchData(...payload));
and changing the method to:
fetchData(id, prop) {
this.$http.get(`serverdata/${id}`)
.then( r => this[`data${prop}`] = r.data)
.catch(err => console.log(err));
}
...but that would be overengineering it.
What I mean by that is that any developer (including yourself, in 6 months from now) looking at this code will spend more time understanding it. And that's actually bad. Always try to write code that's as easy to read/understand as possible. That should be your primary goal. It's a lot more important than it seems.
When you write readable code you're reducing the time you (or others) need to spend modifying it, when they need to. So you're directly saving your company money. That's why code readability is one of the first criteria considered when assessing someone's coding skills.

Method in vue js runs infinitely

I have a method that is called in vue js template. However, when I run the web site, this method is called infinitely
<template>
<div class="strip_list wow fadeIn" v-for="(row, index) in model.data">
<i class="icon_star voted" v-for="(val, index) in getOverallRating(row.id)">
</i>
</div>
</template>
<script>
methods: {
getOverallRating(id)
{
axios.get(`${this.apiReview}?id=${id}`).then(response =>
{
this.overall = response.data
})
return this.overall
}
}
</script>
I expect to give an id of the user, then the method should get an ID send it to the laravel controller, get calculate the rating according the entries in DB and return the result.
So, what you want to do is remove anything that would generate an api call out of your templates loop. What happens is, that every time the data changes, you re-render the template, and since you have an api call in your template, every time you render you request new data, that's why you're getting an infinite loop.
You should store the data you get from the api in a variable, and initiate API calls from outside of the loop.
<template>
<div class="strip_list wow fadeIn" v-for="(row, index) in model.data">
<i class="icon_star voted" v-for="(val, index) in overall(row.id)">
{{val}}
</i>
</div>
</template>
data: () => {
overall: {}
},
methods: {
getAll() {
// loop through all rows and make api request
this.model.data.forEach(r => this.getOverallRating(r.id))
}
getOverallRating(id) {
// make api request
axios
.get(`${this.apiReview}?id=${id}`)
.then(response => {
// and save into overall, where the id is the key
this.overall[id] = response.data
})
},
},
created(){
// initialize loading during create
this.getAll();
}
This can be further improved by not rendering anything 'till all rows are fetched. You could do that by defining another variable in data, that gets populated during getAll, and updated every time the api gets a response. But Ideally you'd be able to call the API for all reviews at once, not one at a time.

Push not updating array in DOM Vue

I am using Vue and am trying to make live search. But on updating the content of search, it doesn't get updated.
Data do get update in array, when checked in dev tools. But DOM don't get updated.
template
<div class="dropdown">
<input type="text" v-model="input" placeholder="Search" #keyup="searching" data-toggle="dropdown">
<span class="caret"></span>
<ul class="dropdown-menu">
<li v-for="(data,index) in availSearchData" :key="index">
{{data.name}}
</li>
</ul>
</div>
method
searching() {
if (this.input) {
let url = this.domain + "search";
axios
.get(url, {
params: {
table: this.table,
data: this.input
}
})
.then(res => {
this.availSearchData = [];
res.data.forEach(doc => {
this.availSearchData.push(doc);
});
});
}
}
I don't know where I am doing wrong.
Please help out if possible.
To add an item to the back of an array and get it to be reactive in Vue, below is what worked for me:
this.$set(this.items,
this.items.length,
JSON.parse(JSON.stringify(this.item))
);
The this.$set is Vue's inbuilt array manipulation function that guarantees reactivity.
The this.items is the array, this.items.length (NOTE: it is items.length NOT items.length - 1) is to push a new index to the back of the array and finally, JSON.parse(JSON.stringify(this.item)) is to clone the this.item into a new object before pushing into the array. The cloning part may not be applicable to you and I used this in variables because all the variables are declared in my data() function.
Use a computed property in your component and use that for parsing the template like this
<li v-for="(data,index) in availSearch" :key="index">
{{data.name}}
</li>
and computed property will be then
availSearch() {
return this.availSearchData;
},
so this computed property always return the array if it is updated.
Also if your response is the array that you want to use exactly, try this
searching() {
if (this.input) {
let url = this.domain + "search";
axios
.get(url, {
params: {
table: this.table,
data: this.input
}
})
.then(res => {
this.availSearchData = [];
Vue.set(this, 'availSearchData', res.data);
});
}
}
Possible explanations for this might be:
You don't declare the property in the component and thus normal
reactivity doesn't work.
You are using index as the key in your array. This might confuse the
reactivity system, so it does not necessarily know if the item
changed. Try using the name of the item as the key instead.
Try calling your function from mounted hook. I think the problem is that you are trying to show data when the DOM is not rendered yet. By calling your function in mounted you get data back after DOM has been rendered.
mounted() {
this.searching();
}
from Vue website "mounted: Called after the instance has been mounted, where el is replaced by the newly created vm.$el. If the root instance is mounted to an in-document element, vm.$el will also be in-document when mounted is called."

Vuejs v-model binding with a select box inside a slot

Good afternoon,
I seem to have occured an issue with v-model binding in scoped slots.
I've tried to create a universal API form that would allow me to hook any URL to it, add any amount and any type of DOM elements inside a scoped slot and use data fetched from API accordingly.
So far I've managed to do the first part - fetch data and pass it to elements inside; the issue I'm having now is thanks to one-way data flow - selecting an option inside of <select></select> doesn't seem to update selectId accordingly - and I get it, that's the pattern it follows... now, how do I work around it?
edit:
If I copy this select directly into the component (without passing via scoped slot) and replce props.* with just * (props.selectedId to selectedId) - it'll work flawlessly.
It only doesn't work because props are one-way.
<template>
<form :action="action" :method="method">
<slot :selectedId="selectedId" :results="results"></slot>
</form>
</template>
<script>
export default
{
props: ['action', 'method', 'url'],
data: () =>
({
results: [],
selectedId: 0,
}),
created()
{
setTimeout(() =>
{
axios.get(this.url).then(response => (this.results = response.data))
}, 500)
},
}
</script>
and HTML:
<api-form action="/blog" method="POST" url="/api/v1/blog">
<template slot-scope="props">
<select class="form-control mb-3" v-model="props.selectedId">
<option v-for="entry, i in props.results" :value="entry">#{{ entry.title }}</option>
</select>
<button class="btn btn-danger">Delete</button>
</template>
</api-form>
Gosh, I keep posting here and finding an answer afterwards.
4 hours of googling - nothing, then I post here and suddenly come up with a solution.
For anyone having the same issue, this is caused by the fact that all non-components, if you apply $emit to it, it'll be called from <Root>, meaning you have to edit your:
created()
{
this.$on('update:selectedId', (value) =>
{
this.selectedId = value
})
},
And change it to this:
created()
{
this.$root.$on('update:selectedId', (value) =>
{
this.selectedId = value
})
},
You can pass a callback as a slot prop that will modify the data being passed also as a slot prop, here's an answer of mine on a similar question v-model and scoped slots not working?