Shibbir
Shibbir

Reputation: 2031

Can't add new item using v-model in Vue JS

I am learning Vue.

Now, I am trying to add data with the price and finally, it calculates total price:

Here is the HTML

<div id="app">  
    <form @submit.prevent="addItem">
        <table border="1" cellpadding="10" width="300">
            <tr>
                <td colspan="2"><strong>Add New Item</strong></td>
            </tr>
            <tr>
                <td>
                    <input type="text" name="" v-model="newItem" placeholder="Item Name">                   
                </td>
                <td>
                    <input type="number" name="" v-model="newItemPrice" placeholder="Item Price">
                </td>
            </tr>           
        </table>
    </form>
    <br>
    <table border="1" cellpadding="10" width="400">
        <tr>
            <th>Item Name</th>          
            <th>Item Price</th>
        </tr>
        <tr v-for="(item, index) in items" :key="index">
            <td>{{ item.name }}</td>
            <td><input type="number" name="" v-model="item.price"></td>
            <td><button @click="removeItem(index)">X</button></td>
        </tr>
        <tr>
            <td>Total</td>
            <td><strong>{{ total }}</strong></td>
        </tr>
    </table>
</div>

Here is the Vue Instance:

new Vue({
    el : '#app',
    data : {
        items: [
            { name: 'Rice', price : 12.60 },
            { name: 'Oil', price : 22.00 },
            { name: 'Mango', price : 32.50 },
            { name: 'Orange', price : 42.00 },
        ],
        newItem : '',
        newItemPrice : '',  
    },
    computed: {
        total() {
            var total = 0;
            this.items.forEach( item => {
                total += parseFloat( item.price );
            })
            return total;
        }
    },
    methods: {
        addItem() {             
            this.items.push({
                name: this.newItem,
                price: 0
            });
        },
        removeItem( index ) {
            this.items.splice( index, 1 )
        }
    }
});

You can see it's by default showing item name and price. I want to add new item using the v-model called newItem But It's not adding the new item to the table

BUT

If I remove the Item Price column I mean this line:

<td>
    <input type="number" name="" v-model="newItemPrice" placeholder="Item Price">
</td>

then it's adding the new item perfectly :(

can you tell me what's wrong here?

Upvotes: 1

Views: 384

Answers (3)

palaѕн
palaѕн

Reputation: 73886

This happens because of browser implementation. As mentioned in W3C Specs:

When there is only one single-line text input field in a form, the user agent should accept Enter in that field as a request to submit the form.

But in case of multiple elements, the enter keypress does not trigger the form submit and thus you get this behaviour.

To resolve this you can simply use @keyup.enter.prevent="addItem" to listen to the enter keypress on each input and call the addItem() function like:

new Vue({
  el: '#app',
  data: {
    items: [{name:"Rice",price:12.6},{name:"Oil",price:22},{name:"Mango",price:32.5},{name:"Orange",price:42}],
    newItem: '',
    newItemPrice: null,
  },
  computed: {
    total() {
      var total = 0;
      this.items.forEach(item => {
        total += parseFloat(item.price);
      })
      return total;
    }
  },
  methods: {
    addItem() {
      this.items.push({
        name: this.newItem,
        price: 0
      });
    },
    removeItem(index) {
      this.items.splice(index, 1)
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<div id="app">
  <form @submit.prevent="addItem">
    <table border="1" cellpadding="10" width="300">
      <tr>
        <td colspan="2"><strong>Add New Item</strong></td>
      </tr>
      <tr>
        <td>
          <input type="text" name="" v-model="newItem" placeholder="Item Name"
            @keyup.enter.prevent="addItem">
        </td>
        <td>
          <input type="number" name="" v-model="newItemPrice" placeholder="Item Price" 
            @keyup.enter.prevent="addItem">
        </td>
      </tr>
    </table>
  </form>
  <br>
  <table border="1" cellpadding="10" width="400">
    <tr>
      <th>Item Name</th>
      <th>Item Price</th>
    </tr>
    <tr v-for="(item, index) in items" :key="index">
      <td>{{ item.name }}</td>
      <td><input type="number" name="" v-model="item.price"></td>
      <td><button @click="removeItem(index)">X</button></td>
    </tr>
    <tr>
      <td>Total</td>
      <td><strong>{{ total }}</strong></td>
    </tr>
  </table>
</div>

Upvotes: 0

aks
aks

Reputation: 9491

See two issues with the fiddle:

  1. There is no way to submit the form data
  2. When pushing the price field was not added to the object

After fixing both of them it works well in this fiddle.

Upvotes: 1

Danizavtz
Danizavtz

Reputation: 3270

You should put a new line in your form, my suggestion is to put just above the close form tag </form>:

<input type="submit" value="add">

Another fix to do is in your methods addItem()

addItem() {             
  this.items.push({
     name: this.newItem,
     price: this.newItemPrice
     });
  }

Where it is the number 0 you should provide the this.newItemPrice to it work properly.

Upvotes: 0

Related Questions