0

I am calculating estimated cost. Selecting a product fetch the details about the product and showing it's description and price on the input box. And then upon clicking in add button a new row will appear for another selection. But the problem is the new row appears with the older row data. And changing a single row affects all other rows. Here is my code so far:

<tbody v-for="row in rows" :key="index">
    <tr>
        <td>
            <select @change="selected" v-model="product_id" class="form-control" name="product_id" id="product_id">
                <option value="">Select Product</option>
                <option v-for="item in items" :value="item.id" v-text="item.product_name"></option>
            </select>                                           
        </td>
        <td>
            <textarea type="text" v-model="product.product_details" name="product_details" id="product_details" class="form-control" rows="1" placeholder="Product Details"></textarea>
        </td>
        <td>
            <input v-model.number="product.product_sellPrice" type="number" step="any" class="form-control" name="rate" id="rate" placeholder="Rate">
        </td>
        <td>
            <input v-model.number="product.product_tax" type="number" step="any" class="form-control" name="tax" id="tax" placeholder="Tax">
        </td>
        <td>
            <input v-model="quantity" type="number" class="form-control" name="quantity" id="quantity" placeholder="Quantity">
        </td>
            
        <td> 
            <input :value="total" type="number" step="any" class="form-control" name="total" id="total" placeholder="Total Price">
        </td>
        <td>
            <button class="btn btn-secondary" v-on:click="addrow" >
                <i class="fa fa-plus" aria-hidden="true"></i>
            </button>
            <button v-show="length > 1" class="btn btn-secondary" @click.prevent="removerow(index)">
                <i class="fa fa-minus" aria-hidden="true"></i>
            </button>
        </td>
    </tr>   
</tbody>

Vue Part

<script>
    export default{
        props: ['products'],

        data() {

            return {
                rows: [{

                }],
            
                items: this.products,
                product: '',
                product_id: '',
                quantity: '',
                index: '',
                total_price: '',
            }
        },
            

        methods: {
            addrow: function (event) {
                event.preventDefault();
                this.rows.push({
                });
            },

            removerow: function (index) {
                this.rows.splice(index, 1);
            },

            selected(e){
                var id = this.product_id;
                console.log(id);
                axios.get('/estimate/product/' + id)
                  .then((response)=>{
                        this.product = '';
                        this.product = response.data;
                  })
                  .catch((error) => {
                        console.log(error);
                  }); 
            },  
        }
    }
</script>  

Where am I doing wrong?

zahid hasan emon
  • 6,023
  • 3
  • 16
  • 28
  • This is a single part of my project. But I think It has no other connection without fetching the data from database with the project. Here is my complete code for this part and I think I am doing wrong in selecting rows – zahid hasan emon Oct 17 '17 at 11:13
  • Get running code working in jsfiddle.net and post here, it will be easier to help you.. How to create a Minimal, Complete, and Verifiable example: https://stackoverflow.com/help/mcve – StefanE Oct 17 '17 at 11:31
  • It will not work in JSFiddle. But I have made the code shorter. – zahid hasan emon Oct 17 '17 at 11:44
  • By creating a bare minimum example can help the troubleshooting, code does not have to reflect your actual service. I do think one problem is that when you add a new row completely empty, add the new row with parameters defined but empty, something like this: this.rows.push({'Param1':''}); – StefanE Oct 17 '17 at 11:56

1 Answers1

1

key should be a unique identifier for each row. You have index defined in the data object and you use it for all the rows as key, that causes problems.

Also it is not recommended to use the row index as a key since it changes when you add/remove rows.

So you need to add some identifier to each row item and use it as the key, here is a simple example of how to do it:

<div id="vue-instance">
  <ul>
    <li v-for="(index,item) in inventory" :key="item.name">
      {{ item.name }} - ${{ item.price }}
      <button @click="add">Add</button>
      <button @click="remove(index)">Remove</button>
    </li>
  </ul>


</div>

var vm = new Vue({
  el: '#vue-instance',
  data: {
    counter: 1,
    inventory: [{
      name: 'MacBook Air',
      price: 1000
    }, {
      name: 'MacBook Pro',
      price: 1800
    }, {
      name: 'Lenovo W530',
      price: 1400
    }, {
      name: 'Acer Aspire One',
      price: 300
    }]
  },
  methods: {
    add: function() {
      this.inventory.push({
        name: 'item' + this.counter++,
        price: this.counter * 1000
      })
    },
    remove: function(index) {
      this.inventory.splice(index, 1);
    }
  }
});

https://jsfiddle.net/1rancd5g/

Tomer
  • 17,787
  • 15
  • 78
  • 137
  • Thanks for your answer. I know the way you have done it. But the thing is I have select option and upon selecting an item I am sending an axios request to get the property of the item. i – zahid hasan emon Oct 18 '17 at 04:48
  • The new code is like this from your suggestion: https://jsfiddle.net/5phq111c/2/ But the problem remains all the same. Where is the problem in the code? – zahid hasan emon Oct 18 '17 at 04:58
  • The new code you posted has the same problem, you are using for the key `row.id`, but row has no id. add an id property to the row. You can look here for how to generate an id: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript – Tomer Oct 18 '17 at 06:51
  • Can I use the row.product_id as the key? And I have bind the product_id with row and sending axios request by product id to get the value. But this is not working. I am getting error 404. How can I catch the id and send the request? The fiddle is https://jsfiddle.net/5phq111c/4/ – zahid hasan emon Oct 18 '17 at 07:17
  • you can bind anything that is unique, regarding the 404, it means the server does not know the url you are calling – Tomer Oct 18 '17 at 07:55
  • Yeah the id of the url is missing. So how can I use the row.product_id as the id of the url in axios request? If I use var id = this.row.product_id and the url is ('/estimate/product/' + id) , this is giving me the error: Uncaught TypeError: Cannot read property 'product_id' of undefined. – zahid hasan emon Oct 18 '17 at 08:42