blob: f0a52600c6d6361bae1dcb2c8b430ff41ec1fcd9 [file] [log] [blame] [edit]
/**
* Composable for table selection utilities
* Extracted from BVTableSelectableMixin for use in Composition API
*/
import { ref, nextTick, watch } from 'vue';
export function useTableSelection(currentPage = ref(1)) {
const selectedRows = ref([]);
const tableHeaderCheckboxModel = ref(false);
const tableHeaderCheckboxIndeterminate = ref(false);
// Watch for page changes and clear selections
// This prevents confusion with checkboxes appearing checked on the new page
watch(currentPage, (newPage, oldPage) => {
if (newPage !== oldPage) {
selectedRows.value = [];
tableHeaderCheckboxModel.value = false;
tableHeaderCheckboxIndeterminate.value = false;
}
});
const clearSelectedRows = (tableRef) => {
if (tableRef) {
tableRef.clearSelected();
selectedRows.value = [];
tableHeaderCheckboxModel.value = false;
tableHeaderCheckboxIndeterminate.value = false;
}
};
const toggleSelectRow = (tableRef, rowIndex) => {
if (tableRef && rowIndex !== undefined) {
const wasSelected = tableRef.isRowSelected(rowIndex);
if (wasSelected) {
tableRef.unselectRow(rowIndex);
} else {
tableRef.selectRow(rowIndex);
}
nextTick(() => {
onRowSelected(tableRef);
});
}
};
const onRowSelected = (tableRef) => {
if (!tableRef) return;
const allItems = tableRef.filteredItems || tableRef.items || [];
const selectedItems = allItems.filter((item, index) => {
return tableRef.isRowSelected(index);
});
selectedRows.value = selectedItems;
const currentPage = 1;
const perPage = allItems.length;
const startIndex = (currentPage - 1) * perPage;
const endIndex = Math.min(startIndex + perPage, allItems.length);
const pageItemsCount = endIndex - startIndex;
const selectedOnPageCount = selectedItems.filter((item) =>
allItems
.slice(startIndex, endIndex)
.some((pageItem) => pageItem === item),
).length;
if (selectedOnPageCount === 0) {
tableHeaderCheckboxIndeterminate.value = false;
tableHeaderCheckboxModel.value = false;
} else if (selectedOnPageCount === pageItemsCount) {
tableHeaderCheckboxIndeterminate.value = false;
tableHeaderCheckboxModel.value = true;
} else {
tableHeaderCheckboxIndeterminate.value = true;
tableHeaderCheckboxModel.value = true;
}
};
const onChangeHeaderCheckbox = (tableRef, event) => {
/*
* Bootstrap Vue Next Migration:
* Handle header checkbox to select/deselect all rows on current page.
*/
if (!tableRef) return;
const isChecked =
typeof event === 'boolean' ? event : event?.target?.checked;
if (isChecked) {
const allItems = tableRef.filteredItems || tableRef.items || [];
const endIndex = allItems.length;
for (let i = 0; i < endIndex; i++) {
tableRef.selectRow(i);
}
} else {
tableRef.clearSelected();
selectedRows.value = [];
tableHeaderCheckboxModel.value = false;
tableHeaderCheckboxIndeterminate.value = false;
}
nextTick(() => {
onRowSelected(tableRef);
});
};
return {
selectedRows,
tableHeaderCheckboxModel,
tableHeaderCheckboxIndeterminate,
clearSelectedRows,
toggleSelectRow,
onRowSelected,
onChangeHeaderCheckbox,
};
}