I’m trying to fetch product data from a JSON file, but can’t get it to work. I’ve tried several things and searched the internet for a solution but none of the examples on the internet equals my situation. I’m new to both vue and axios, so please excuse my ignorance.
This is what I have so far:
Vue.component('products',{ data: { results: [] }, mounted() { axios.get("js/prods.json") .then(response => {this.results = response.data.results}) }, template:` <div id="products"> <div class="productsItemContainer" v-for="product in products"> <div class="productsItem"> <div class=""> <div class="mkcenter" style="position:relative"> <a class="item"> <img class="productImg" width="120px" height="120px" v-bind:src="'assets/products/' + product.image"> <div class="floating ui red label" v-if="product.new">NEW</div> </a> </div> </div> <div class="productItemName" > <a>{{ product.name }}</a> </div> <div class="mkdivider mkcenter"></div> <div class="productItemPrice" > <a>€ {{ product.unit_price }}</a> </div> <div v-on:click="addToCart" class="mkcenter"> <div class="ui vertical animated basic button" tabindex="0"> <div class="hidden content">Koop</div> <div class="visible content"> <i class="shop icon"></i> </div> </div> </div> </div> </div> </div> ` }) new Vue({ el:"#app", });
The json file is as follows
{ "products":[ { "name": "Danser Skydancer", "inventory": 5, "unit_price": 45.99, "image":"a.jpg", "new":true }, { "name": "Avocado Zwem Ring", "inventory": 10, "unit_price": 123.75, "image":"b.jpg", "new":false } ] }
The problem is only with the fetching of the data from a JSON file, because the following worked:
Vue.component('products',{ data:function(){ return{ reactive:true, products: [ { name: "Danser Skydancer", inventory: 5, unit_price: 45.99, image:"a.jpg", new:true }, { name: "Avocado Zwem Ring", inventory: 10, unit_price: 123.75, image:"b.jpg", new:false } ], cart:0 } }, template: etc.........
Advertisement
Answer
As the warnings suggest, please do the following:
- Rename the data array from
results
toproducts
since you are referencing it by the latter one as a name during render. - Make your data option a function returning an object since data option must be a function, so that each instance can maintain an independent copy of the returned data object. Have a look at the docs on this.
Vue.component('products', { data() { return { products: [] } }, mounted() { axios .get("js/prods.json") .then(response => { this.products = response.data.products; }); }, template: ` //... ` }
<div id="products"> <div class="productsItemContainer" v-for="product in products"> <div class="productsItem"> ...
Also, since you’re not using CDN (I think), I would suggest making the template a component with a separate Vue file rather than doing it inside template literals, something like that:
Products.vue
<template> <div id="products"> <div class="productsItemContainer" v-for="product in products"> <div class="productsItem"> <!-- The rest of the elements --> </div> </div> </div> </template> <script> export default { name: 'Products', data() { return { products: [] } }, mounted() { axios .get("js/prods.json") .then(response => { this.products = response.data.products; }); } } </script>
And then in your main JS file or anywhere else requiring this component:
import Products from './components/Products.vue'; new Vue({ el: '#app', data() { return { //... } }, components: { Products } })
<div id="app"> <Products /> </div>