I'm initially rendering some objects from an API call to my database, they are serialized and look like this initially:
<h3>Messages on Database</h3>
<p v-if="messages.length ===0">No Messages</p>
<div class="msg" v-for="(msg, index) in messages" :key="index">
<p class="msg-index">[{{index}}]</p>
<p class="msg-subject" v-html="msg.subject" v-if="!msg.editing"></p>
<p><input type="text" v-model="msg.subject" v-if="msg.editing" ></p>
<p>{{msg.editing}}</p>
<p class="msg-body" v-html="msg.body" v-show="!messages[index].editing"></p>
<p><input type="text" v-model="msg.body" v-show="messages[index].editing" ></p>
<input type="submit" @click="deleteMsg(msg.pk)" value="Delete" />
<input type="submit" @click="EditMsg(index)" value="Edit" />
<input type="submit" @click="updateMsg(msg.pk)" value="Update" />
</div>
</div>
</template>
<script>
export default {
name: "Messages",
data() {
return {
subject: "",
msgBody: "",
messages: [],
};
},
each message looks like this:
notice that body, pk and subject are the Django model fields. Each item in the array represents a database object.
What I want to do using vue.js, is allow users to edit each item. If the user clicks the edit button for an item, I want to transform its element from p to input, and submit that to the database.
In order to allow editing of individual items, I need an editing field in each item in the array, so I'm doing this in my mounted() property:
mounted() {
this.fetchMessages();
},
methods: {
fetchMessages() {
this.$backend.$fetchMessages().then(responseData => {
this.messages = responseData;
this.messages.forEach(function (value) {
value['editing'] = false;
});
console.log(this.messages);
});
},
Now, when I load up the array in my console, I see this:
So I assumed that now, when the user clicks the Edit button, EditMsg is called, and the fields will transform according to the v-if/v-show directives:
EditMsg(msgIdx) {
this.messages[msgIdx].editing = true;
console.log(this.messages);
},
But that's not happening. What is actually happening is this: the editing flag for the item is changed to true in the console/vue-developer-tools window, but nothing changes in the HTML.
What am I missing?
Full code:
<template>
<div class="hello">
<img src='@/assets/logo-django.png' style="width: 250px" />
<p>The data below is added/removed from the Postgres Database using Django's ORM and Restframork.</p>
<br/>
<p>Subject</p>
<input type="text" placeholder="Hello" v-model="subject">
<p>Message</p>
<input type="text" placeholder="From the other side" v-model="msgBody">
<br><br>
<input type="submit" value="Add" @click="postMessage" :disabled="!subject || !msgBody">
<hr/>
<h3>Messages on Database</h3>
<p v-if="messages.length ===0">No Messages</p>
<div class="msg" v-for="(msg, index) in messages" :key="index">
<p class="msg-index">[{{index}}]</p>
<p class="msg-subject" v-html="msg.subject" v-if="!msg.editing"></p>
<p><input type="text" v-model="msg.subject" v-if="msg.editing" ></p>
<p>{{msg.editing}}</p>
<p class="msg-body" v-html="msg.body" v-show="!messages[index].editing"></p>
<p><input type="text" v-model="msg.body" v-show="messages[index].editing" ></p>
<input type="submit" @click="deleteMsg(msg.pk)" value="Delete" />
<input type="submit" @click="EditMsg(index)" value="Edit" />
<input type="submit" @click="updateMsg(msg.pk)" value="Update" />
</div>
</div>
</template>
<script>
export default {
name: "Messages",
data() {
return {
subject: "",
msgBody: "",
messages: [],
};
},
mounted() {
this.fetchMessages();
},
methods: {
fetchMessages() {
this.$backend.$fetchMessages().then(responseData => {
this.messages = responseData;
this.messages.forEach(function (value) {
value['editing'] = false;
});
console.log(this.messages);
});
},
postMessage() {
const payload = { subject: this.subject, body: this.msgBody };
this.$backend.$postMessage(payload).then(() => {
this.msgBody = "";
this.subject = "";
this.fetchMessages();
});
},
deleteMsg(msgId) {
this.$backend.$deleteMessage(msgId).then(() => {
this.messages = this.messages.filter(m => m.pk !== msgId);
this.fetchMessages();
});
},
EditMsg(msgIdx) {
this.messages[msgIdx].editing = true;
console.log(this.messages);
},
updateMsg(msgId) {
console.log(this.subject, this.msgBody);
const payload = { subject: this.subject, body: this.msgBody };
this.$backend.$putMessage(msgId, payload).then(() => {
this.fetchMessages();
}
)
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
hr {
max-width: 65%;
}
.msg {
margin: 0 auto;
max-width: 30%;
text-align: left;
border-bottom: 1px solid #ccc;
padding: 1rem;
}
.msg-index {
color: #ccc;
font-size: 0.8rem;
/* margin-bottom: 0; */
}
img {
width: 250px;
padding-top: 50px;
padding-bottom: 50px;
}
</style>

