1

Trying to create a dynamic form with a list of each product from a db. The form has the following fields for each product: product title, product price, quantity and total price. My issue is in the fact that I'm not sure how to add a v-model field for each product quantity input, since the list is being pulled from a v-for of all of the products. Here is part of my ProductsListForm vue component template:

<div v-for="product in products" :key="product.id" class="flex form-group">

  <div class="flex p-title">
    <label :for="product.title">{{ product.title }}</label>
    <small>{{ product.price }}$</small>
  </div>

  <div class="flex p-input">
    <input class="input" type="number" :name="product.title" v-model="quantity">
  </div>

  <div class="flex p-total">
    <span>Total: {{  product.price * quantity}}</span>
  </div>

</div>


export default {
  props: ['products'],
  data() {
      return {
          quantity: 0,
      }
  },
  methods: {}
}

So my question is how can I bind quantity to each individual product? Right now, it obviously changes whenever ANY of the input fields are updated... Any help will be greatly appreciated!

4
  • Is quantity an information that each product has? Does it work when you refer to it as product.quantity? Commented Jan 20, 2019 at 9:17
  • v-modeling the property of an array item works, as you can see in this Fiddle: jsfiddle.net/Yovar/nj0w7oye/3 Commented Jan 20, 2019 at 9:34
  • @Yovar quantity is unrelated to each product. It's a variable associated with the form itself. When I try to do it that way, the total is NaN Commented Jan 20, 2019 at 9:37
  • @Yovar the form is intended to act like a shopping list. A customer inputs how many of each product (quantity) so having quantity as a db field for each product is not the intended purpose Commented Jan 20, 2019 at 9:42

2 Answers 2

1

Rather than using v-model, you could instead listen for the input events on each element.

new Vue({
  el: '#app',
  data: () => ({
    cart: [],
    products: [{
        id: 1,
        name: 'foo'
      },
      {
        id: 2,
        name: 'bar'
      },
      {
        id: 3,
        name: 'baz'
      }
    ]
  }),
  methods: {
    updateCart(event, product) {
      const index = this.cart.findIndex(i => i.name === product.name)

      const item = {
        name: product.name,
        quantity: event.target.value
      }

      if (index !== -1) {
        this.cart.splice(index, 1, item)
      } else {
        this.cart.push(item)
      }
    }
  }
})
ul,
li {
  list-style: none;
}

#app {
  display: flex;
  flex-direction: row;
  justify-content: space-around;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div>
    <h5>products</h5>
    <ul>
      <li v-for="product in products" :key="product.id">
        <label>{{ product.name }}</label>
        <input @input="updateCart($event, product)" min="0" type="number">
      </li>
    </ul>
  </div>
  <div>
    <h5>cart</h5>
    <ul v-if="cart.length">
      <li v-for="item in cart" :key="item.id">
        <p>{{ item.name }} {{ item.quantity }}</p>
      </li>
    </ul>
    <p v-else>no items in cart</p>
  </div>
</div>

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

Comments

1

For the quantity to be related to the product (entry of products) - you will have to pass it to the products or make it an array by itself.

<div v-for="product in products" :key="product.id" class="flex form-group">

  <div class="flex p-title">
    <label :for="product.title">{{ product.title }}</label>
    <small>{{ product.price }}$</small>
  </div>

  <div class="flex p-input">
    <input class="input" type="number" placeholder="1" :name="product.title" v-model="quantity[product.id]">
  </div>

  <div class="flex p-total">
    <span>Total: {{  product.price * getProductQuantity(product) }}</span>
  </div>

</div>


export default {
  props: ['products'],
  data() {
      return {
          quantity: [],
      }
  },
  methods: {
    getProductQuantity(product) {
      return this.quantity[product.id] || 0;
    }
  }
}

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.