Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

boyjarv's avatar

how can I delete and remove item from a list?

Here is my method:

async deleteTodo(id) {
      try {
        res = await axios.delete(`todo/${id}`);
        let z = this.todoDetails
          .map((todoDetails) => todoDetails.id)
          .indexOf(id);
        this.todoDetails.splice(z, 1);
        console.log("RES: " + res);
      } catch (error) {
        console.log(error);
      }
      // this.isOpen = true;
      // this.isEdit = true;
    },

but because I am inside a child component, I am getting: Unexpected mutation of "todoDetails" prop

0 likes
9 replies
MohamedTammam's avatar
Level 51

Don't mutate props. Instead emit an event and do that in the parent component.

$emit('remove', z);

And in your parent component

<child :todoDetails="todoDetails" @remove="todoDetails.splice(z, 1)" />
boyjarv's avatar

@MohamedTammam Ok so in my ListItems.vue component I put:

<Todo
        v-if="type == 'todo'"
        :todoDetails="item"
        data-item="todo"
        @remove="todoDetails.splice(z, 1)"
      />

then in my Todo component:

deleteTodo(id) {
      Swal.fire({
        title: "Are you sure?",
        text: "You won't be able to revert this!",
        icon: "warning",
        showCancelButton: true,
        confirmButtonColor: "#3085d6",
        cancelButtonColor: "#d33",
        confirmButtonText: "Yes, delete it!",
      }).then((result) => {
        if (result.isConfirmed) {
          Swal.fire("Deleted!", "Your file has been deleted.", "success");
          axios.delete(`todo/${id}`);
          $emit("remove", z);
        }
      });
      // this.isOpen = true;
      // this.isEdit = true;
    }

it's still the same?!

MohamedTammam's avatar

@boyjarv Yeah, it's. Instead of removing the element from the child you remove it from the parent.

1 like
tykus's avatar

Assign the prop todoDetails to a new data property, and mutate that instead. Also, use filter rather than map

props: {
  todoDetails: Array
},
data() {
  return {
    todo_details: this.todoDetails
  }
},
async deleteTodo(id) {
      try {
        res = await axios.delete(`todo/${id}`);
        let z = this.todo_details
          .filter((todoDetails) => todoDetails.id === id)
        console.log("RES: " + res);
      } catch (error) {
        console.log(error);
      }
      // this.isOpen = true;
      // this.isEdit = true;
    },
boyjarv's avatar

I am now getting: Uncaught (in promise) TypeError: this.todo.filter is not a function at eval (Todo.vue?7a9e:72:1)

this is what I have now:

<template>
  <div class="bg-gray-200 h-100 p-4 rounded m-4">
    <div class="my-2">
      <span class="font-bold">({{ todo.id }})&nbsp;{{ todo.title }}</span
      ><br />
      {{ todo.description }}<br />
    </div>
    <div class="flex flex-row items-center justify-between">
      <router-link :to="`/contact/${todo.id}`">
        <AppButton
          type="delete"
          :processing="isLoading"
          @click.prevent="deleteTodo(todo.id)"
          data-element="button"
          >Delete&nbsp;&nbsp;<i class="fa-solid fa-trash"></i
        ></AppButton>
      </router-link>
    </div>
    <ModalWindow :open="isOpen" @close="closeModal()">
      <AddEditForm
        :editing="isEdit"
        :todoDetails="todoDetails"
        @close="closeModal()"
      />
    </ModalWindow>
  </div>
</template>

<script>
import Swal from "sweetalert2";
import { ref } from "vue";
import axios from "axios";
import AppButton from "@/components/AppButton.vue";
import ModalWindow from "@/components/ModalWindow.vue";
import AddEditForm from "@/components/contact/AddEditForm.vue";
export default {
  components: {
    AppButton,
    ModalWindow,
    AddEditForm,
  },
  name: "ContactDetails",
  props: {
    todoDetails: {},
  },
  data() {
    return {
      title: "",
      description: "",
      isOpen: ref(false),
      isEdit: false,
      todo: this.todoDetails,
    };
  },
  methods: {
    deleteTodo(id) {
      Swal.fire({
        title: "Are you sure?",
        text: "You won't be able to revert this!",
        icon: "warning",
        showCancelButton: true,
        confirmButtonColor: "#3085d6",
        cancelButtonColor: "#d33",
        confirmButtonText: "Yes, delete it!",
      }).then((result) => {
        if (result.isConfirmed) {
          Swal.fire("Deleted!", "Your file has been deleted.", "success");
          axios.delete(`todo/${id}`);
          let z = this.todo.filter((todo) => todo.id).indexOf(id);
          this.todo.splice(z, 1);
        }
      });
      // this.isOpen = true;
      // this.isEdit = true;
    },
    closeModal() {
      this.isOpen = !this.isOpen;
    },
  },
};
</script>
boyjarv's avatar

ahh... but my delete button is in the child object component?!

boyjarv's avatar

ok so my ListItems:

<Todo
        v-if="type == 'todo'"
        :todoDetails="item"
        data-item="todo"
        @remove="todoDetails.splice(z, 1)"
      />

and my Todo Component:

if (result.isConfirmed) {
          Swal.fire("Deleted!", "Your file has been deleted.", "success");
          axios.delete(`todo/${id}`);
          let z = this.todo.filter((todo) => todo.id).indexOf(id);
          $emit("remove", z);
        }

it's still not working?!

boyjarv's avatar

I managed to sort it in the end thank you!

Please or to participate in this conversation.