2
votes

I'm cloning an array and using map to add a property to each object in the array. For some reason when I do this the added property is not being updated when used in v-model. Any ideas why this is happening?

In the below code typing in the text field does not update the item quantity. How can the code be altered so that it does?

<template>
  <v-data-table
    :headers="headers"
    :items="items"
  >
    <template v-slot:item.quantity="props">
      <v-text-field v-model="props.item.quantity"></v-text-field>
    </template>
  </v-data-table>
</template>

<script>
export default {
  props: {
    customer: {
      type: Object,
      required: true
    }
  },
  data: () => ({
    headers: [
      { text: 'ID', value: 'id' },
      { text: 'Description', value: 'description' },
      { text: 'Quantity', value: 'quantity' },
    ],
    items: []
  }),
  created() {
    this.initialize()
  },
  methods: {
    initialize() {
      const items = [...this.customer.items]
      items.map(item => {
        item.quantity = ''
      })
      this.items = items
    }
}
</script>

Customer is a JSON response from API

{
  "id": 1,
  "name": "Customer",
  "items": [
    {
      "id": 1,
      "product": 1707,
      "contract": null,
      "plu": "709000",
      "description": "ABC",
      "unit": 1,
      "price": "5.20"
    }
  ],
}

Update

Link to codepen - typing in the qty2 field does not update the data because it was added to the object with map.

2
Try with v-slot:item.quantity="{ item }" v-model="item.quantity". - azeós
Can you please share the sample object of this.customer.items, in question, that would really help to solve your issue - chans
@azeós that doesn't work either - bdoubleu
@chans question updated - bdoubleu
The above approach will update the object , when you change the value in text box - chans

2 Answers

1
votes

The above code is working as expected, I've reproduced the same scenario in codepen

find the working code here: https://codepen.io/chansv/pen/gOOWJGJ?editors=1010

Try make changes to the first text box in the data-table for testing purpose and check the console it updates the items object on typing

<div id="app">
  <v-app id="inspire">
    <v-data-table
      :headers="headers"
      :items="desserts"
      :items-per-page="5"
      class="elevation-1"
    >
      <template v-slot:item.protein="props">
        <v-text-field
          v-model="props.item.protein"
          name="quantity"
          outlined
          @input="getdata"
          type="number"
        ></v-text-field>
      </template>
    </v-data-table>
  </v-app>
</div>


new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data () {
    return {
      headers: [
        {
          text: 'Dessert (100g serving)',
          align: 'left',
          sortable: false,
          value: 'name',
        },
        { text: 'Calories', value: 'calories' },
        { text: 'Fat (g)', value: 'fat' },
        { text: 'Carbs (g)', value: 'carbs' },
        { text: 'Protein (g)', value: 'protein' },
        { text: 'Iron (%)', value: 'iron' },
      ],
      desserts: [
        {
          name: 'Frozen Yogurt',
          calories: 159,
          fat: 6.0,
          carbs: 24,
          protein: 4.0,
          iron: '1%',
        },
        {
          name: 'Ice cream sandwich',
          calories: 237,
          fat: 9.0,
          carbs: 37,
          protein: 4.3,
          iron: '1%',
        },
        {
          name: 'Eclair',
          calories: 262,
          fat: 16.0,
          carbs: 23,
          protein: 6.0,
          iron: '7%',
        },
        {
          name: 'Cupcake',
          calories: 305,
          fat: 3.7,
          carbs: 67,
          protein: 4.3,
          iron: '8%',
        },
        {
          name: 'Gingerbread',
          calories: 356,
          fat: 16.0,
          carbs: 49,
          protein: 3.9,
          iron: '16%',
        },
        {
          name: 'Jelly bean',
          calories: 375,
          fat: 0.0,
          carbs: 94,
          protein: 0.0,
          iron: '0%',
        },
        {
          name: 'Lollipop',
          calories: 392,
          fat: 0.2,
          carbs: 98,
          protein: 0,
          iron: '2%',
        },
        {
          name: 'Honeycomb',
          calories: 408,
          fat: 3.2,
          carbs: 87,
          protein: 6.5,
          iron: '45%',
        },
        {
          name: 'Donut',
          calories: 452,
          fat: 25.0,
          carbs: 51,
          protein: 4.9,
          iron: '22%',
        },
        {
          name: 'KitKat',
          calories: 518,
          fat: 26.0,
          carbs: 65,
          protein: 7,
          iron: '6%',
        },
      ],
    }
  },
  methods: {
    getdata() {
      console.log(this.desserts[0].protein);
    }
  },
})
0
votes

The solution is that you need to do a deep copy of the customer.items before using map to add the new object property.

initialize() {
  let items = JSON.parse(JSON.stringify(this.customer.items))
  items.map(item => {
    item.quantity = '5'
    return item
  })
  this.items = items
}