0👍
It sounds like what you want is a component which you toggle to be either in a read-only mode, or in a mode which accepts input for your admin users. You can then use this in your v-for
loop to bind to the array of data.
You can still use v-model
with custom components to facilitate two-way binding as described here. Basically, v-model
will supply the value to the component via the value
property, and will listen for an input
event from the component to receive updates to the value.
So, our component template could look like the below, which conditionally renders an input field if the prop edit
is true, otherwise it renders a read-only span element. We bind the value of the input
to a local mutable data item we initialise from the value
prop v-model
will pass in from the parent. On the input
event as the user changes the value, it will in turn emit an event of the same name so the parent component can receive updates.
<input
v-if="edit"
type="text"
v-model="localValue"
@input="$emit('input', $event.target.value)"
class="form-control" />
<span v-else>{{ value }}</span>
With a backing script like this:
var customInputComponent = {
template: '#input-template',
props: ["edit", "value"],
data() {
return {
localValue: this.value
}
}
};
In the parent element, the usage of the component in the template would look like this, where we register the custom input component with the name appCustomInput
. We use v-model
to bind the component to the current item of the iteration and the property for that particular column. Finally, we bind the edit
prop of the custom component to a data field editMode
on the parent with :edit="editMode"
(short cut for v-bind:edit="editMode"
).
It is important to set the :key="searchResult.id"
to uniquely identify each entry, otherwise there will be problems when updating the DOM when the value changes. We can’t use just the index
for this, because if we remove an item from the courses array, it will no longer be correct. So, I’ve added a unique id
property to each of the course objects.
<tr v-for="(searchResult, index) in searchCourses" :key="searchResult.id">
<th scope="row">
{{ index + 1 }}
</th>
<td>
<app-custom-input v-model="searchResult.topic" :edit="editMode" />
</td>
<td>
<app-custom-input v-model="searchResult.description" :edit="editMode" />
</td>
<td v-if="editMode">
<button
v-if="editMode"
class="btn btn-secondary"
@click="deleteRow(searchResult.id)">Delete</button>
</td>
</tr>
The backing instance code for this would look something like this:
new Vue({
el: "#app",
components: {
appCustomInput: customInputComponent
},
data: {
search: '',
editMode: false,
courses: [
{ topic: "English", description: "Universal language", id: 1 },
{ topic: "Maths", description: "Numbers etc.", id: 2 },
{ topic: "Physics", description: "Falling apples etc.", id: 3 },
{ topic: "Chemistry", description: "Periodic table etc.", id: 4 }
]
},
methods: {
deleteRow(sourceId) {
var index = this.courses.findIndex(a => a.id == sourceId);
this.courses.splice(index, 1);
}
},
computed: {
searchCourses() {
return this.courses
.filter((item) => {
return item.topic
.toLowerCase()
.includes(this.search.toLowerCase())
});
}
}
});
A complete code pen is available here for demonstration.
0👍
The {{ }}
"mustache" syntax is used to display values, so the expression between the double braces will be evaluated and the output will replace it. This is a one-way process. You’re most likely looking for a two-way binding which does not only change your UI if the property changs, but also change the property when a user changes it from the UI, hence the name.
Have a look at Input bindings. Where v-model
is the key:
<input v-model="item.topic">