Vue.js - How to use v-for in JSON array? - javascript

I have JSON output from server:
[
{"id":"2","name":"Peter","age":"24"},
{"id":"4","name":"Lucy","age":"18"},
]
and now I want to use it with v-for directive, but it doesn't work for me.
Here is my export default:
data () {
return {
info: {}
}
},
mounted () {
axios
.get('http://localhost:4000/fetch.php/')
.then(response => (this.info = response.data))
},
And now if I want to display output of info, it works well {{ info }}.
But I need to use v-for directive and display only names.
<p v-if="info.name">{{ info.name }}</p>
But it is not working, only what is working is this: {{ info[0].name }}.

You cannot read the name property directly like this: info.name. Since the output is an array of objects rather than a single object.
data () {
return {
info: [], // make this an empty array
}
},
mounted () {
axios
.get('http://localhost:4000/fetch.php/')
.then(response => (this.info = response.data))
},
Then, you can render the info array in your template using v-for directive:
<ul v-if="info.length">
<li v-for="item in info" :key="item.id">{{ item.name }}</li>
</ul>
Read more about List Rendering in Vue.

Related

VueJS and nested v-for: How to get endpoint data through each loop?

I am using VUEJS to build a single page application. I have a single file component that gets some data from an API (using Axios) and uses v-for to render out a list like so:
<template>
<div>
<ul>
<li v-for="division in divisions" :key="division.id_PK">
{{ division.c6code }} - XXX
</li>
</ul>
</div>
</template>
props: {
country: {
type: Object,
required: true
}
},
data() {
return {
divisions: [],
},
methods: {
async getDivisions() {
const divisions = await APIService.getDivisions(
this.country.igpeSID_FK
)
this.divisions = divisions
},
}
An example of the API data source looks like /getDivisions/800001:
{
"status": 200,
"data": [
{
"id_PK": 205891,
"igpeSID_FK": 800001,
"c6code": "AB-CDE"
},
{
"id_PK": 205890,
"igpeSID_FK": 800001,
"c6code": "FG-HIJ"
},
{
"id_PK": 205889,
"igpeSID_FK": 800001,
"c6code": "KL-MNO"
},
{
"id_PK": 205888,
"igpeSID_FK": 800001,
"c6code": "PQ-RST"
},
{
"id_PK": 205887,
"igpeSID_FK": 800001,
"c6code": "WX-YZA"
}
]
}
The rendered UI looks like so:
Now, there is another API endpoint that contains additional data that I need to put in place of the "XXX" placeholder shown above. That additional data source has a property called name and contains the actual division name which was not included in the /getDivisions API (only the associated property id_PK is provided).
Question: How can I get this name for each division?
An example of this endpoint that contains the additional data is: /getDivisionNameById/{id_PK} where id_PK is the parameter I need to pass to it from the getDivisions data shown above. So, for example, if I pass 205891 to the /getDivisionNameById/205891 I get back data that looks like so:
Example /getDivisionNamesById/205891:
{
"status": 200,
"data": [
{
"P_uniqueID": 16919,
"isoGeoDivisionEntry_FK": 205891,
"name": "ZABUL",
"lang": "fa"
},
{
"P_uniqueID": 16918,
"isoGeoDivisionEntry_FK": 205891,
"name": "ZABUL",
"lang": "ps"
}
]
}
I am thinking that I need to create a function that somehow creates a new array of names that I could then loop through in yet another v-for in my original template like so:
<li v-for="division in divisions" :key="division.id_PK">
{{ division.c6code }} - <span v-for="divName in divisionNames" :key="division.id_PK">{{divName.name}}</span>
</li>
async getDivisionNameById(id_PK) {
const name = await APIService.getDivisionNameById(id_PK)
this.divNames.push(name)
}
Obviously, I don't know what I am doing there...
Codesandbox with data:
https://codesandbox.io/s/intelligent-wind-21w35?file=/src/getDivisionNamesById.json
You have to query the data first before rendering the content.
You could fetch all the data in onMounted hook.
Thats a good place for a computed property.
Edit this example as needed depending on how you call your APIs.
You could call both API endpoints in the mounted lifecycle-hook of the component. Included this with a simple timeout to simulate the data coming in at different times.
About the secondary API call(s) where you get the name-data: As you've already said, loop through the IDs and make the API calls. In this case you'd need to wait for the result of your first API call and then use those ID's it returns to make the second API call(s). Maybe this will help you with the await/asyc/then stuff:
How to use async/await in Vue.js?
<template>
<div class="hello">
<ul>
<li v-for="(division, index) in fullList" :key="index">
{{ division }}
</li>
</ul>
</div>
</template>
<script>
import divisions from "#/getDivisionsEntries.json";
import divisionNames from "#/getDivisionNamesById.json";
export default {
name: "DivisionsList",
data() {
return {
divisions: divisions.data,
divisionNames: null,
};
},
mounted() {
setTimeout(() => {
this.divisions = divisions.data;
}, 1000);
setTimeout(() => {
this.divisionNames = divisionNames.data;
}, 3000);
},
computed: {
fullList: function () {
let combinedArr = [];
for (var divi of this.divisions) {
var divNameData = this.divisionNames?.find(
(x) => x.isoGeoDivisionEntry_FK === divi.id_PK
);
if (divNameData !== undefined) {
combinedArr.push(`${divi.c6code} - ${divNameData.name}`);
}
}
return combinedArr;
},
},
};
</script>

HTML in Vue.js not updating after axios get request updates object's property

HTML in Vue.js not updating after axios get request. HTML is:
<span #click="tryResponse">
Data_object: {{ data_object }} <br>
Data_object.serial: {{ data_object.serial }} <br>
</span>
data:
data(){
return{
data_object: {},
}
},
method:
methods: {
tryResponse() {
axios.get('http://127.0.0.1:8000/source/groups/15').then((response) => {
this.data_object.serial = response.data});
}
This is all happening in a file called App.vue (if that is important).
If I look in chrome dev tools Vue, I can see the data object does update and populate with the correct information. But it doesn't update in the html on the page.
Edit:
Everything works fine if I do:
this.data_object = response.data
But the problem comes when I do this:
this.data_object.serial = response.data
The property serial is never declared on the vue instance and therefore is not reactive.
You could use Vue.set(this.data_object, "serial", response.data) this registers it with vue so it will add observers to this variable and it will become reactive
or
declare the serial property on the data object
data(){
return{
data_object: {
serial: ""
},
}
},
Here's a link about reactivity in Vue

Filtering items using a condition (vue.js)

This is now solved
The problem
I am trying to make a filter that does this.
Gets 'name' from session storage and matches it with 'name' on product.
I'm storing all 'logged in' user data on 'sessionStorage' for practice.
I'm storing all the 'products' in 'localStorage'
I'm just doing this as a small project to understand and practice vue & js.
Basically if the product has been created by user x, upon login, user x should only be able to see the products he listed and not the rest of the products.
This is what I can do
I can get the user info from sessionStorage and when creating a product, the user 'name' is passed on along with the product details.
I can also retrieve all the products from localStorage.
I don't know how to come up with a filter using vue.js that does this.
Some code sample would really help me understand whats going on.
Additionally, I want to display the results in html.
Thanks in advance.
},
computed: {
filteredProducts() {
this.products.filter(x => x.name === this.loggedUser[0].user);
}
},
});```
[1]: https://i.stack.imgur.com/W7PMf.png
computed: {
filteredProducts() {
return this.products.filter(x => x.name === this.loggedUser[0].text); // text or user, whichever field is for username
},
},
After that show the list in html use v-for.
<p v-if="filteredProducts.length === 0">No products found</p>
<li v-for="(product, key) in filteredProducts" :key="key">Product: {{ product.description }}, Price {{ product.price }} <button #click="deleteProduct(key)">Delete</button></li>
add delete method
methods: {
// ...
deleteProduct(index) {
this.products.splice(index, 1);
},
}
I think this may work from you (given what you have provided above)
computed: {
filteredProducts () {
return this.products.filter(function (item) {
return (item.name === this.loggedUser[0].name)
}
}
}
Basically, we are filtering the products based on the name that is tagged on that list with the loggedUser name.
Hope this helps.

How can I unbind data from a v-data-table when a v-select is null?

I have a v-data-table that gets its data from a vuex-store. The data thats displayed is controlled by a v-select on the same page. So when a user selects a company in the v-select the v-data-tables data gets updated with users.
My problem is that when a user selects a company in the v-select and then goes to another page, upon reentering the page the data is still there, but the v-select does not have any company selected, so the view is out of sync.
How can I "reset" the v-data-table to not show any data upon reentering the page? I have bound my vuex-store to the v-data-table with a computed property, so I cannot set it to null. Any ideas
<template>
<v-select
v-bind:items="listOfLocations"
v-model="selectedLocation"
label="Kontor"
item-value="locationid"
item-text="name"
single-line
bottom
ref="thisOne"
autocomplete></v-select>
<v-data-table
:headers="headers"
:items="listOfCompanys"
hide-actions
class="elevation-1">
<template slot="items" slot-scope="props">
<td>{{ props.item.customerid }}</td>
<td>{{ props.item.name }}</td>
</template>
</v-data-table>
<script>
import { FETCH_LOCOMPANY_LIST, FETCH_LOCATION_LIST, REMOVE_COMPANY, ADD_NEW_COMPANY } from '../store/actions.type'
export default {
name: 'Companies',
data: () => ({
selectedLocation: null,
}),
watch: {
selectedLocation: function (val, oldval) {
this.$store.dispatch(FETCH_LOCOMPANY_LIST, val)
}
},
mounted: function () {
this.$store.dispatch(FETCH_LOCATION_LIST)
if (this.selectedLocation === null || this.selectedLocation === undefined) {
this.listOfCompanys = null
}
},
computed: {
listOfLocations () {
return this.$store.state.companies.locationList
},
listOfCompanys () {
return this.$store.state.companies.companyList
}
}
The way of doing what you are doing it looks strange to me.Try to use another way.Anyway,you said that your problem is that when the user reentering the page the data is still there.So one way would be:
In your component,when the user leave the page, try clear the data.So use lifecycle hook:beforeDestroy there you can dispatch an action to clear the property in store that is related companies (if i get the question well)
How about executing watch immediately on load:
watch: {
selectedLocation: {
immediate: true,
handler(val, oldval) {
this.$store.dispatch(FETCH_LOCOMPANY_LIST, val)
}
...
I think this should be same as initial load (when user opens the page for the first time).
What about this:
1) Create a 'reset' mutation in the store for the company list:
mutation: {
resetCompanies (state) {
state.companies.companyList = [];
}
}
2) Call this mutation on the mounted () function:
mounted () {
this.$store.commit('resetCompanies');
}
So i think i get it.You want to have a v-select and upon on this the table filled.
You said that the table filled with users.But the "users" are static or you are getting them from Database?
if you are getting from Database then:
data: {
select: '',
selectItems: [1,2,3],
dataTableItems: []
},
watch: {
select() {
//here make a request to backend like below
axios.get('/users', {params: {select: this.select}})
.then(response=> {
//here fill the data-table
this.dataTableItems = response.data.users
})
}
You dont have why to use vuex store.Also if you are filling the select from backend then in created hook fill the select items like:
created() {
axios.get('locations')
.then(response => {
this.selectItems = response.data.locations
})
}

How should I take a multidimensional array in vuejs?

This problem has made me sleep well in two days.
This is my code with vuejs & axios & nuxt:
<template>
<ul>
<li v-for="item in data.apilist.interfaces" :key="item" v-if="data.apilist.interfaces">
{{ item.name }}
</li>
</ul>
</template>
<script>
import axios from 'axios'
const util = require('util')
export default {
data: () => ({
title: ''
}),
async asyncData ({ params, error }) {
let res = await axios.get(
`https://bird.ioliu.cn/v1?url=https://api.steampowered.com/ISteamWebAPIUtil/GetSupportedAPIList/v1/`
)
return { data: util.inspect(res, { showHidden: true, depth: null }) }
},
head () {
return {
title: this.title
}
}
}
</script>
Json data : https://api.steampowered.com/ISteamWebAPIUtil/GetSupportedAPIList/v1/
No matter how I do it, I can't get the value of apilist->interfaces->name.
The above example code system prompts me Cannot read property'interfaces' of undefined , which part is the problem?
===================update
I have installed chrome vue dev, but it seems to work on nuxt applications. Now I try to print the entire data data.
The data generated when I typed the corresponding connection directly in the browser is as follows:
enter image description here
But strange things happen, and when I jump to this link from somewhere else in the application, the data data is like this:
enter image description here
I tried v-for="item in data.apilist" {{item.interfaces.name}} or v-if="data.apilist" or v-if="data" and he no longer complains but no data is generated.
This is the result of the powershell output:
enter image description here && enter image description here
Cannot read property'interfaces' of undefined
Simply means that you are trying to access to the property "interfaces" on a undefined reference : somethingThatDoesntExist.interfaces
Here is the mess :
<li v-for="item in data.apilist.interfaces" :key="item" v-if="data.apilist.interfaces">
{{ data.interfaces }}
</li>
You are iterating on data.apilist.interfaces and binding just beneath :
data.interfaces
But you need to bind
item.interfaces
Since you are using v-for="item in ..." and not v-for="data in ...".
Code review is important before asking.

Categories

Resources