I have a vue file, where I have a checkbox for every row (corresponds to each object), which when clicked needs to toggle and hit the patch api. When clicked the checkbox, the item.id and checked=true needs to be passed in the async function. But when I check the console, the ItemId is undefined and also in network tab, the api has /undefined/ in the pk param.
The template is here..
<template>
<div
class="modal fade"
id="manageLocationModal"
tabindex="-1"
aria-labelledby="manageLocationLabel"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="manageLocationModalLabel">
Locations List
</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="modal-body px-4">
<div class="collapse mb-4 border p-4" id="editLocation">
<location-edit-form
:item="item"
@updated="itemUpdated"
@cancel="cancelUpdate"
></location-edit-form>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>S/N</th>
<th>Local Name</th>
<th>Latitude</th>
<th>Longitude</th>
<th>Variable</th>
<th>Altitude</th>
<th>Municipality</th>
<th>Owners Name</th>
<th>Operational</th>
<th>Ward</th>
<th>Started Date</th>
<th>End Date</th>
<th>Uploaded At</th>
<th class="text-center">Actions</th>
<th>Publish</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in location" :key="item.id">
<th scope="row" v-if="meta.currentPage > 1">
<p v-if="index !== 9">
{{ meta.currentPage - 1 }}{{ ++index }}
</p>
<p v-else>
{{ ++index * meta.currentPage }}
</p>
</th>
<th v-else scope="row">
{{ ++index }}
</th>
<td>{{ item.Localname }}</td>
<td>{{ item.latitude }}</td>
<td>{{ item.longitude }}</td>
<td v-if="item.variable.length">
{{ item.variable | filterVariableName }}
</td>
<td v-else>N/A</td>
<td>{{ item.Altitude }}</td>
<td>{{ item.Municipality }}</td>
<td>{{ item.owners_name }}</td>
<td>{{ item.Operational }}</td>
<td>{{ item.Ward }}</td>
<td>{{ item.Started_date }}</td>
<td>{{ item.End_date }}</td>
<td>{{ item.uploaded_at }}</td>
<td class="text-center">
<button
class="btn btn-primary btn-sm me-3 mb-3"
@click.prevent="editLocation(item)"
:disabled="isUpdating"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Edit"
>
<i class="bi bi-pencil-square"></i>
</button>
<button
class="btn btn-danger btn-sm"
:disabled="isUpdating"
@click.prevent="deleteLocation(item.location_id)"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Delete"
>
<i class="bi bi-trash-fill"></i>
</button>
</td>
<td class="text-center">
<input
type="checkbox"
v-model="item.selectedItems"
:value="item.id"
@change="handleCheckboxChange(item.id, $event.target.checked)"
:checked="selectedItems.includes(item.id)"
/>
</td>
</tr>
</tbody>
</table>
<nav>
<ul class="pagination" v-if="meta.totalPages > 1">
<li
class="page-item"
v-if="meta.currentPage !== 1 && meta.totalPages > 1"
>
<button
class="page-link"
@click.prevent="getData(--meta.currentPage)"
:disabled="meta.currentPage === 1"
>
Previous
</button>
</li>
<li
v-for="i in meta.totalPages"
class="page-item"
:class="{ active: meta.currentPage === i }"
:key="i"
>
<a class="page-link" href="#" @click.prevent="getData(i)">{{
i
}}</a>
</li>
<li
class="page-item"
v-if="
meta.currentPage !== meta.totalPages && meta.totalPages > 1
"
>
<button
class="page-link"
@click.prevent="getData(++meta.currentPage)"
:disabled="meta.currentPage >= meta.totalPages"
>
Next
</button>
</li>
</ul>
</nav>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
Close
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import LocationEditForm from "../../components/forms/LocationEditForm.vue";
export default {
name: "ManageLocationModal",
components: { LocationEditForm },
data() {
return {
editCollapse: null,
isUpdating: false,
location: [],
selectedItems: [], // Array to store selected item IDs
meta: {
totalItems: 0,
totalPages: 0,
currentPage: 1,
pageSize: 10,
},
item: null,
};
},
mounted() {
this.getData();
},
filters: {
filterVariableName(val) {
const variable = val.map((el) => {
return el.variable;
});
return variable;
},
},
methods: {
collapseEditForm(type) {
if (!this.editCollapse) {
this.editCollapse = new this.$bootstrap.Collapse(
document.getElementById("editLocation")
);
}
if (type === "show") {
this.editCollapse.show();
} else {
this.editCollapse.hide();
}
},
collapseEditLocationForm() {
this.collapseEditForm("hide");
this.item = null;
this.isUpdating = false;
},
itemUpdated() {
this.collapseEditLocationForm();
this.getData();
this.$emit("itemUpdated");
},
cancelUpdate() {
this.collapseEditLocationForm();
},
async deleteLocation(id) {
await this.$confirm({
message: `Are you sure?`,
button: {
no: "No",
yes: "Yes",
},
callback: (confirm) => {
if (confirm) {
this.$repository.location
.delete(id)
.then(() => {
this.getData();
this.$emit("itemUpdated");
this.$toast.success("Location deleted");
})
.catch(() => {
this.$toast.error("Deletion failed");
});
}
},
});
},
editLocation(item) {
this.isUpdating = true;
this.item = item;
this.collapseEditForm("show");
},
async getData(page = 1) {
this.meta.currentPage = page;
let params = `?page_size=${this.meta.pageSize}&ordering=-uploaded_at`;
if (this.meta.currentPage > 1) {
params += `&page=${this.meta.currentPage}`;
}
await this.$repository.location.filter(params).then((res) => {
this.location = res.data.results;
this.meta.totalItems = res.data.count;
this.meta.totalPages = Math.ceil(res.data.count / 10);
});
},
async handleCheckboxChange(itemId, isChecked) {
console.log("Checkbox changed:", { itemId, isChecked });
if (!itemId) {
console.error("Item ID is undefined");
return;
}
this.isUpdating = true;
try {
if (isChecked) {
console.log("Checkbox checked. Item ID:", itemId);
// Check if the item is already in the selectedItems list
if (!this.selectedItems.includes(itemId)) {
this.selectedItems.push(itemId);
}
// Publish the item if checked
await this.$repository.location.edit({ in_draft: false }, itemId);
this.$toast.success("Location published successfully.");
} else {
console.log("Checkbox unchecked. Item ID:", itemId);
// Remove the item from the selectedItems list
if (this.selectedItems.includes(itemId)) {
this.selectedItems = this.selectedItems.filter(
(id) => id !== itemId
);
}
}
} catch (error) {
this.$toast.error(
`Error: ${error.response?.data?.error || error.message}`
);
} finally {
this.isUpdating = false;
}
},
},
};
</script>
<style scoped>
.modal-dialog {
max-width: 85%;
overflow: initial !important;
}
.modal-body {
height: 80vh;
overflow-y: auto;
}
.actions {
min-width: max-content;
}
</style>
The code snippet of focus here is :
<input
type="checkbox"
v-model="item.selectedItems"
:value="item.id"
@change="handleCheckboxChange(item.id, $event.target.checked)"
:checked="selectedItems.includes(item.id)"
/>
And the async function handleCheckboxChange is called.
The screenshot of console is here.