/** * 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, }; }