Vue.js pushing object to array changes every element in the array to be identical

Viewed 834

I am building a Vue.js application that allows a user to make and view a feed of products.

I have a parent element NewFeed which allows a user to have a name for their feed, and then allows a user to push products into this feed. The child element NewProduct allows the user to input data for the product, then pushes into the parent's products array. I have noticed that every time I push a new product into the array, every element in the array is changed to be the value of the new element.

How do I change this so that the elements remain as they were originally input?

NewFeed (Parent Element):

Vue.component('NewFeed', {
  data: function() {
    return {
      newFeed: {
        name: "",
        products: []
      },
    }
  },
  methods: {
    addProduct: function(p) {
      p.id = this.pushedProducts;
      this.newFeed.products.push(p);
    }
  },
 template: `
    <div class="">
      <label for='feedNameInput'/>Feed Name: </label>
      <input id='feedNameInput' v-bind:value='newFeed.name' v-on:input='newFeed.name = $event.target.value'/> <br>
      <ViewProduct v-for='product in newFeed.products' :key='product.id'></ViewProduct>
      <NewProduct v-on:pushProduct='addProduct($event)'></NewProduct>
      <button v-on:click='pushNewFeed'>Add Feed</button>
    </div>
`});

NewProduct (Child Element)

Vue.component('NewProduct', {
  data: function() {
    return {
      newProduct: { id: 0 }
    }
  },
  methods: {
    addProduct: function() {
       this.$emit('pushProduct', this.newProduct);
       this.newProduct.id++;
    }
  },
  template: `
    <div class='newProduct'>
      <label for='productNameInput'/>Product Name: </label>
      <input id='productNameInput' v-bind:value='newProduct.name' v-on:input='newProduct.name = $event.target.value'/> <br>

      <label for='productOriginalPriceInput'>Original Price: </label>
      <input id='productOriginalPriceInput' v-bind:value='newProduct.originalPrice' v-on:input='newProduct.originalPrice = $event.target.value'/><br>

      <label for='productNewPrice'>New Price: </label>
      <input id='productNewPrice' v-bind:value='newProduct.newPrice' v-on:input='newProduct.newPrice = $event.target.value'/><br>

      <label for='productDiscountAmount'>Discount Amount: </label>
      <input id='productDiscountAmount' v-bind:value='newProduct.discountAmount' v-on:input='newProduct.discountAmount = $event.target.value'/><br>

      <label for="productImage">Upload Image: </label>
      <input type='file' accept='image/*' id='productImage' v-bind:file='newProduct.imageFile' v-on:change='newProduct.imageFile = $event.target.files[0];'/><br><br><br>

      <button v-on:click="addProduct">Add Product</button>
    </div>
`});
1 Answers

This happens because the child component emits the same object reference each time (JavaScript objects are passed by reference). So all of the emitted objects are the same object. You have to create a brand new object each time. Maybe the simplest way to do that is to reset the child object right after you emit:

addProduct: function() {
   this.$emit('pushProduct', this.newProduct);
   const id = this.newProduct.id + 1;
   this.newProduct = { id }
}
Related