0

I am building a shoe shop with Vue and the problem is that I am getting undefined when reloading the page when I am trying to access a getter through computed property on the ShoeDetail component.I am storing some hard coded array of objects data in the vuex state. In the Shoe component I am looping through the data with v-for and outputting in the Men view, that is working for me, all avaliable shoes are displayed. When a user clicks on the shoe image a new route is loaded for each shoe with further details for that shoe which got clicked. I am using the id for dynamic routing. Now i have a getter in vuex

getProductById: (state) => (id) => {
      return state.sneakers.find((sneaker) => sneaker.productId === id);
    },

then I access it through a computed property:

   product() {
      return this.$store.getters.getProductById(this.$route.params.id);
    },

that works fine and I can output the data stored in vuex state by interpolitaion like:

{{product.brand}}

When I reload the page I get this error:

**[Vue warn]: Error in render: "TypeError: Cannot read property 'brand' of undefined"
found in
---> <Detail> at src/components/ShoeDetail.vue
       <App> at src/App.vue
         <Root>**

I have tried to use v-if="product" but since im not making an API call this shouldn't be relevant. I have also installed the createPersistedState but it still doesn't work. I am really stuck here and a hint on why im getting undefined on page reload would be appreciated

My vuex:

    import Vue from 'vue';
    import Vuex from 'vuex';
    import createPersistedState from 'vuex-persistedstate';

    Vue.use(Vuex);

    export default new Vuex.Store({
      plugins: [
        createPersistedState({
          key: 'keyname',
          storage: window.localStorage,
        }),
      ],
      state: {
        sneakers: [
          {
            productId: 1,
            productno: 1234,
            brand: 'nike',
            gender: 'men',
            size: 5,
            price: 150,
            image: require('@/assets/images/nike-air-zoom.jpg'),
          },
          {
            productId: 2,
            productno: 1235,
            brand: 'adidas',
            gender: 'men',
            size: 10,
            price: 140,
            image: require('@/assets/images/sneakers.jpg'),
          },

          {
            productId: 3,
            productno: 1236,
            brand: 'adidas',
            gender: 'men',
            size: 10,
            price: 130,
            image: require('@/assets/images/man-holding-nikes.jpg'),
          },
          {
            productId: 4,
            productno: 1237,
            brand: 'nike',
            gender: 'men',
            size: 5,
            price: 120,
            image: require('@/assets/images/nike-air-zoom.jpg'),
          },
          {
            productId: 5,
            productno: 1238,
            brand: 'adidas',
            gender: 'men',
            size: 10,
            price: 110,
            image: require('@/assets/images/sneakers.jpg'),
          },

          {
            productId: 6,
            productno: 1239,
            brand: 'adidas',
            size: 10,
            price: 100,
            image: require('@/assets/images/man-holding-nikes.jpg'),
          },
        ],
      },
      getters: {
        getProducts: (state) => {
          return state.sneakers;
        },
        getProductById: (state) => (id) => {
          return state.sneakers.find((sneaker) => sneaker.productId === id);
        },
      },
    });

The Shoe component:

    <template>
      <div class="shoe-container">
        <div class="shoe-card" v-for="element in products" :key="element.id">
          <router-link
            :to="{ name: 'ShoeDetail', params: { id: element.productId } }"
            ><img :src="element.image" tag="img" alt="" class="shoe-card__image"
          /></router-link>
          <p class="shoe-card__model">{{ element.brand }}</p>
          <p class="shoe-card__price">{{ element.price }} $</p>
        </div>
      </div>
    </template>

    <script>
    export default {
      computed: {
        products() {
          return this.$store.getters.getProducts;
        },
        product() {
          return this.$store.getters.getProductById(this.$route.params.id);
        },
      },
    };
    </script>

    <style lang="scss" scoped>
    @import '../sass/components/shoe';
    </style>

The men view:

    <template>
      <div>
        <navbar></navbar>
        <sub-nav></sub-nav>
        <filter-section></filter-section>
        <section class="shoes">
          <shoe></shoe>
        </section>
      </div>
    </template>

    <script>
    import Navbar from "../components/Navbar.vue";
    import SubNav from "../components/SubNav.vue";
    import FilterSection from "../components/FilterSection.vue";
    import Shoe from "../components/Shoe.vue";

    export default {
      components: {
        Navbar,
        SubNav,
        FilterSection,
        Shoe
      }
    };
    </script>

    <style lang="scss" scoped>
    @import "../sass/views/men";
    </style>

The ShoeDetail component:

    <template>
      <div class="details">
       
        <h1>This is details</h1>
        <h2>{{ product.brand }}</h2>

      </div>
    </template>
    <script>
    export default {
      name: 'detail',

      computed: {
        product() {
          return this.$store.getters.getProductById(this.$route.params.id);
        },
      },
    };
    </script>

    <style lang="scss" scoped>
    @import '../sass/components/shoeDetail';
    </style>
2
  • I'd debug the product computed property to see what's going on at the time when it returns undefined. What is the value of this.$route.params.id at that time? If it is a string, then doing === comparison against a number won't match. Commented Apr 28, 2020 at 12:18
  • Thanks for the answer! You are completely right it was a string, used parseInt to change it to a number! Commented Apr 28, 2020 at 12:31

2 Answers 2

1

Thanks for the answer I was able to fix it by adding parseInt in the computed property of ShoeDetail.

  computed: {
    product() {
      return this.$store.getters.getProductById(
        parseInt(this.$route.params.id)
      );
    },
  }

Sign up to request clarification or add additional context in comments.

Comments

0

Do this in the ShoeDetail component:

data: () => {
    data: '',
},
methods: {
    getProduct () {
    this.product = this.$store.getters.getProductById(this.$route.params.id);
    },
},
mounted () {
    this.getProduct();
}

and it should work :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.