Home > front end >  Vue changes to array not updating the DOM
Vue changes to array not updating the DOM

Time:11-17

I'm trying to make changes to an array in the parent component (insert and update data) that is passed to the child component via Props, but the DOM is not being updated.

Parent component:

<UsersList
  v-for="(role, i) in userRolesNames"
  :key="i"
  :users="usersPages[i].data"
/>

Child component:

<template>
<div
  v-for="user in users"
  :key="user.id"
>
  <span>{{ user.name }}</span>
  <div>
    <i
      class="bi bi-pen-fill edit-icon m-pointer"
      @click="onClickEdit(user)"
    ></i>
    <i
      class="bi bi-trash-fill delete-icon ms-2 m-pointer"
      @click="onClickDelete(user)"
    ></i>
  </div>
</div>
</template>
<script lang="ts">
// recieving the array
props: {
  users: {
    required: true,
    type: Array as PropType<usersType[]>
  }
}
</script>

Each user basically has the following structure:

{
  id: x,
  name: 'x',
  email: 'x',
  login: 'x',
  role: x
}

The problem is that when trying to insert or update a record in the usersPages[i].data array, the DOM doesn't change. If I use the Vue developer tools, the data is changing correctly, but the DOM isn't.

Tried inserting using the push method on the array but without success. The only thing that worked was this:

const newUser = response.data;
const page = this.usersPages[newUser.role - 1];
Vue.set(page, 'data', [...page.data, newUser]);

To update I tried to directly change the user properties, but like the insert the DOM doesn't update. What worked was:

const page = this.usersPages[user.role - 1];
const oldUsers = page.data.filter(u => u.id != user.id);
Vue.set(page, 'data', [ ...oldUsers, response.data ]);

Works but doesn't look right... Can anyone help?

CodePudding user response:

I had a similar problem before. I believe that this is a bug in vue. The reason for this is that Vue rendered the v-for already. Vue as of now does not know how to handle the changes in the array. What I did as a workaround for this is have a updateKey variable inside my script set to 0. Then increment this variable every time we update the array updateKey . And we use this key for our component.

On child component,

<template>
<span
  v-for="user in users"
  :key="user.id"
>
  <div :key="updateKey">
    <span>{{ user.name }}</span>
    <div>
      <I
        class="bi bi-pen-fill edit-icon m-pointer"
        @click="onClickEdit(user)"
      ></i>
      <I
        class="bi bi-trash-fill delete-icon ms-2 m-pointer"
        @click="onClickDelete(user)"
      ></i>
    </div>
  </div>
</span>
</template>

and onClickEdit(user) and onClickDelete(user) make sure you have updateKey

CodePudding user response:

The DOM won't update because you are not doing it reactively. To update this value reactively you should listen to some event (input for example), that you'll emit in the child component and pass the new(!) value to your property. But a better way is to bind your components via v-model.

P.S. - So you can see changes in the devtools because this is not a part of the Vue lifecycle, it`s just like a parser that watches actual data, but without context.

  • Related