Mayana
Mayana

Reputation: 15

Editing an item in an array with vue js

I'm a newbie and I fetched some data from firebase and after being able to display, add and delete them successfully. I also want to edit them and update them to firebase again.

So I bind the post I wish to edit to an input wth v-model, called an editPost function on the edit button and I also passed in the index but the issue I'm having is that if I clicked the edit button on one of the posts it is also firing the other edit buttons

This is my template:
<div v-for="(post, i) in posts" :key="i">
    <h3>By: {{ post.name }}</h3>
    <p>
      {{ post.post }}
    </p>
    <p>{{ post.date }}</p>
    
    <button @click="deletePost(i)">delete</button>

    <button v-if="editMode" @click="editPost(i)">Edit</button>
    
    <input type="text" v-if="!editMode" v-model="post.post">
    <button v-if="!editMode" @click="savePost">Save</button>
    <button v-if="!editMode" @click="cancleEditMode">Cancle</button>
</div>

This is where I called the editPost function:

  const editMode = ref(true)
  const postItem = ref("")

  const editPost = (i) => {
    editMode.value = false
    postItem.value = posts.value.find((post) => post.i === i)

    console.log(i)
  }

Upvotes: 0

Views: 192

Answers (1)

Tim
Tim

Reputation: 391

You are on the right track! One thing I notice right away is that you are using the index as the key which is fine for learning and experimentation. However, when it comes to updating the item in the database, index is irrelevant. You should use the item id instead which is also the key in the database.

It appears from this snippet that your UI is dependent on the variable editMode which is true on page load. Upon clicking editPost that variable turns false as executed by your editPost() function. Reason I mention this is because I assume you wish to only put a single item or 'post' in edit mode. However, as it is written now, you are changing the state for the entire component, therefore every post will be in edit mode.

The easiest way to fix this would only modify your code a touch. Alternatively, you could implement Vuex/Pinia for global state management, or refactor the post to another component with its own state. For simplicity, I'm showing the first option here.

<div v-for="(post, id) in posts" :key="id">
    
 <button @click="deletePost(id)">delete</button>

 <div v-if="post === postItemToEdit">   
   <input type="text" v-model="post.post">
   <button @click="savePost">Save</button>
   <button @click="cancleEditMode">Cancle</button>
 </div>

  <button v-else @click="editPost(post)">Edit</button> 
</div>

<script>
  const postItemToEdit = ref()

  const editPost = (post) => {
    postItemToEdit.value = post
    console.log(postItemToEdit)
  }
</script>

Note grouping inputs in one v-if div so as not to repeat the v-if each time. Also using v-else for simplicity on the alternative option.

Upvotes: 1

Related Questions