3

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.........
7
  • What do you see in the console? Also, you will want to v-for the results rather than products, unless that is a typo... Commented Feb 9, 2019 at 17:40
  • The console shows the following: vue.js:616 [Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions. Commented Feb 9, 2019 at 17:49
  • and<br> vue.js:616 [Vue warn]: Property or method "products" 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. See: vuejs.org/v2/guide/…. found in ---> <Products> <Root> Commented Feb 9, 2019 at 17:49
  • Are you running Vue with CDN? Commented Feb 9, 2019 at 17:54
  • No I downloaded it. Both Vue and Axios work properly. The problem isnt with the files. The following displays the correct data in the console axios.get('/js/products.json') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }) .then(function () { // always executed }); Commented Feb 9, 2019 at 17:57

1 Answer 1

4

As the warnings suggest, please do the following:

  1. Rename the data array from results to products since you are referencing it by the latter one as a name during render.
  2. 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>
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.