Henri
Henri

Reputation: 1741

Vue3 - Table not updating after deleting an array item, need to refresh the page to see effect

My table is not updating while I'm removing one of its element.

My Vue page:

<template>
    <div class="home">
        <div class="py-10">

            <header>
                <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
                <h1 class="text-3xl font-bold leading-tight text-gray-900">Items</h1>
                </div>
            </header>
            <main>
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
          <div class="flex flex-col">
            <div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
                <div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
                    <div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
                    <table class="min-w-full divide-y divide-gray-200">
                        <thead class="bg-gray-50">
                        <tr>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                Name
                            </th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                Hostname
                            </th>
                            <th scope="col" class="relative px-6 py-3">
                                <span class="sr-only">Actions</span>
                            </th>
                        </tr>
                        </thead>
                        <tbody>
                            <tr v-for="(item, index) in items.value" :key="index" :class="index % 2 === 0 ? 'bg-white' : 'bg-gray-50'">
                                <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ item._source.name }}</td>
                                <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ item._source.hostname }}</td>
                                <td class="px-6 py-4 whitespace-nowrap text-right text-sm">
                                    <div class="flex flex-row-reverse">
                                        <div @click="deleteItem(item._id)" class="px-1 text-red-600 hover:text-red-900">
                                            <TrashIcon class="h-5 w-5"/>
                                        </div>
                                    </div>
                                </td>
                            </tr>
                        </tbody>
                        
                </table>
                </div>
            </div>
            </div>
        </div>
        </div>
      </main>

        </div>
    </div>
</template>

<script>
import { ref } from '@vue/reactivity'
import { TrashIcon } from '@heroicons/vue/outline'
import ItemsService from '../../services/items.service'
export default {
    name: 'ReadItems',
    components: {
        TrashIcon,
    },
    data(){
        return {
            items: ref([]),
        }
    },

    async mounted(){
        this.items.value = await this.readItems()
    },

    methods: {
        async readItems(){
            let temp = null
            try {
                temp = await ItemsService.readItems()
                temp = temp.data.body.hits.hits
            } catch (error) {
                console.log('Error: could not retrieve all items.')
            }
            return temp
        },

        async deleteItem(itemId){
            await ItemsService.deleteItem({ _id: itemId })
            await this.readItems()
        }
    }
}
</script>

When I run the deleteItem method, I need to reload page to see the item disappeared. I would like to see it without having to reload the page...

Upvotes: 1

Views: 1367

Answers (1)

Nikola Pavicevic
Nikola Pavicevic

Reputation: 23490

Don't use ref from composition API in data function in options API, here the data is already reactive :

const app = Vue.createApp({
  data() {
    return {
      items: [],
    };
  },
  async mounted(){
    this.items = await this.readItems()
  },
  methods: {
    async readItems(){
      let temp = null
      try {
        // setTimeout emulates async call
        setTimeout(() => this.items = [{_id: '1', _source: {name: 'aaa', hostname: 'aaa'}}, {_id: '2', _source: {name: 'bbb', hostname: 'bbb'}}, {_id: '3', _source: {name: 'ccc', hostname: 'ccc'}}], 2000)
        //temp = await ItemsService.readItems()
        //temp = temp.data.body.hits.hits
      } catch (error) {
        console.log('Error: could not retrieve all items.')
      }
      return temp
    },
    async deleteItem(itemId){
      // setTimeout emulates async call
      setTimeout(() => this.items = this.items.filter(i => i._id !== itemId), 1000)
      //await ItemsService.deleteItem({ _id: itemId })
    }
  }
})
app.mount('#demo')
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" integrity="sha512-wnea99uKIC3TJF7v4eKk4Y+lMz2Mklv18+r4na2Gn1abDRPPOeef95xTzdwGD9e6zXJBteMIhZ1+68QC5byJZw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://unpkg.com/vue@next"></script>
<div id="demo">
  <div class="home">
    <div class="py-10">
      <header>
        <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <h1 class="text-3xl font-bold leading-tight text-gray-900">Items</h1>
        </div>
      </header>
      <main>
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
          <div class="flex flex-col">
            <div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
              <div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
                <div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
                  <table class="min-w-full divide-y divide-gray-200">
                    <thead class="bg-gray-50">
                      <tr>
                        <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                          Name
                        </th>
                        <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                          Hostname
                        </th>
                        <th scope="col" class="relative px-6 py-3">
                          <span class="sr-only">Actions</span>
                        </th>
                      </tr>
                    </thead>
                      <tbody>
                        <tr v-for="(item, index) in items" :key="index" :class="index % 2 === 0 ? 'bg-white' : 'bg-gray-50'">
                          <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ item._source.name }}</td>
                          <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ item._source.hostname }}</td>
                          <td class="px-6 py-4 whitespace-nowrap text-right text-sm">
                            <div class="flex flex-row-reverse">
                              <div @click="deleteItem(item._id)" class="px-1 text-red-600 hover:text-red-900 cursor-pointer">
                                <!--<TrashIcon class="h-5 w-5"/>-->
                                delete
                              </div>
                            </div>
                          </td>
                        </tr>
                     </tbody>
                  </table>
                </div>
              </div>
            </div>
          </div>
        </div>
      </main>
    </div>
  </div>
</div>

Upvotes: 1

Related Questions