0

I've come across a problem. I'm trying to code a shopping cart. I have 4 components:

  • LivingRoom.vue (where all products from Product are displayed)
  • Product.vue (template with name, description and price for each product),
  • ProductDetails.vue (details for each product)
  • ShoppingCart.vue.

Each product in ProductDetails has button with addToCart function, which takes as an argument item prop. Every time I try to add a new product (object) to the array, the previous one is probably replaced by the new one. I make a deep copy of each object by using Vue.util.extend, so that quantity property is updated. And this works fine. But when I try to add different item to the cart array, the previous item disappears and the new one shows. I'm using EventBus and cart is emitted from the ProductDetails component to the ShoppingCart Component.

I helped myself by using this codepen: https://codepen.io/anon/pen/BEEwqd There everything works fine.

I'm fetching the data from local (static/products.json).

I tried to import project from github to codesandbox in order to make everything easier for you, but somehow it doesn't work as expected, therefore I'm pasting a link to my repo:

https://github.com/rafalpyska/weeklywebdevchallange10

LivingRoom.vue

<template lang="html">
  <div class="container">

      <transition-group tag="section" class="products" name="list">
        <Product
          v-for="item in dataToDisplay"
          :item="item"
          :key="item.id"
          @click.native="handleProductDetails(item)"
        />
      </transition-group>

    </main>

    <ProductDetails
      v-if="isProductDetailsOpen"
      :item="itemDetails"
      :data="data"
    />

</template>

<script>
  const API = '/static/products.json';

  export default {
    name: 'LivingRoom',
    data() {
      return {
        status: true,
        data: [],
        dataToDisplay: [],
        itemDetails: null,
      }
    },
    components: {
      Product,
      ProductDetails
    },
    created() {
      axios.get(API)
        .then((response) => {
          this.data = response.data[0].category[0];
          for (let key in this.data) {
            if (!this.data.hasOwnProperty(key)) continue;
            this.dataToDisplay = this.data[key];
          }
          this.status = false;
        })
    },
    methods: {
      handleProductDetails(item) {
        this.isProductDetailsOpen = true;
        this.itemDetails = item;
      }
    }

Product.vue

<template lang="html">
    <div>
      <p>class="products__name">{{ name }}</p>
      <p class="products__description">{{ description)</p>
      <p class="products__price">${{ price }}</p>
    </div>
</template>

<script>
  export default {
    name: "Product",
    props: {
      item: {
        required: true
      }
    },
    data() {
      return {
        name: this.item.title,
        description: this.item.description,
        price: this.item.price,
      }
    }
  };
</script>

ProductDetails.vue

<template lang="html">
  <section class="product-details">
    <h2 class="product__name">{{ name }}</h2>
    <label for="quantity">Quantity</label>
    <input class="input__quantity" id="quantity" max="10" min="1" name="quantity" type="number"
                     v-model.number="item.quantity">
    <button @click="addToCart(item)" class="btn">Add to cart</button>
  </section>
</template>

<script>
  import Vue from 'vue'
  import {EventBus} from "@/event-bus.js";

  export default {
    name: "ProductDetails",
    props: {
      item: {
        type: Object,
        required: true
      },
      data: {
        type: Object,
        required: true
      }
    },
    data() {
      return {
        cart: [],
        name: this.item.title,
        id: this.item.id,
        quantity: this.item.quantity
      }
    },
    methods: {
      addToCart(productToAdd) {
        let found = false;
        this.cart.forEach((item) => {
          if (item.id === productToAdd.id) {
            found = true;
            item.quantity += productToAdd.quantity;
          }
        });
        if (found === false) {
          this.cart.push(Vue.util.extend({}, productToAdd));
        }
        productToAdd.quantity = 1;
        EventBus.$emit('update-cart', this.cart);
      }
    }
  };
</script>

ShoppingCart.vue

<template lang="html">
        <div class="cart" v-for="item in cart">
          <div class="cart__product-info">
            <p></p>
            <p class="item__title">Product: {{ item.title }}</p>
            <p class="item__quantity">Quantity: {{ item.quantity }}</p>
          </div>
        </div>
      </div>
    </section>
</template>

<script>
  import {EventBus} from "@/event-bus.js";

  export default {
    name: "ShoppingCart",
    data() {
      return {
        cart: null
      }
    },
    created() {
      EventBus.$on('update-cart', (item) => {
        this.cart = item;
      });
    }
  }

products.json

[
  {
    "category": {
      "0": {
        "title": "Living Room",
        "id": 1
        "products": {
          "0": {
            "title": "Red Seat",
            "id": 1,
            "description": "Armless Task Chair with Adjustable Height and Swivel Functionality. Comfortable 2 inches thick cushioned back and seat. 360 degrees swivel functionality. Pneumatic seat height adjustment. Upholstered in an easy to clean fabric. Dual wheel caster for any type of flooring",
            "price": "45",
            "image": "images/redseat.png",
            "quantity": 1
          },
          "1": {
            "title": "White Table",
            "id": 2,
            "description": "International Concepts Solid Wood Dining Table with Shaker Legs",
            "price": "350",
            "image": "images/whitetable.png",
            "quantity": 1
          }
        }
      }
    }
]
Rafix
  • 18
  • 1
  • 3

1 Answers1

0

cart: [] is always an empty array for each ProductDetails? So when you pushing an item to it, the maximum length is 1

One possible solution is changing update-cart listener

EventBus.$on('update-cart', (item) => {
  const newItem = item[0]
  this.cart = this.cart || []
  let found = false
  this.cart = this.cart.map(oldItem => {
    if (oldItem.id === newItem.id) {
      found = true
      return newItem
    }
    return oldItem
  })
  if (!found) {
    this.cart = this.cart.concat(item)
  }
});
ittus
  • 21,730
  • 5
  • 57
  • 57
  • Unfortunately, it doesn't work.The same situation as I mentioned at the beginning. Quantity property of object is modified and changes are visible in the cart, however if I move to the next item and try to add it, it replaces the previous one. – Rafix May 01 '19 at 00:31
  • Considering `Vue.util.extend`, I was sure it does deep copy. https://stackoverflow.com/questions/30578254/does-vue-js-have-a-built-in-way-to-add-a-copy-of-a-persistent-object-to-a-repeat – Rafix May 01 '19 at 00:37
  • `cart: []` is always an empty array for each `ProductDetails`? So when you pushing an item to it, the maximum length is 1 – ittus May 01 '19 at 00:50
  • Yes, looking at vue dev tools, actually each ProductDetails item has an empty array. So what should I do? – Rafix May 01 '19 at 01:01