1/** 2 * Composable for table selection utilities 3 * Extracted from BVTableSelectableMixin for use in Composition API 4 */ 5 6import { ref, nextTick, watch } from 'vue'; 7 8export function useTableSelection(currentPage = ref(1)) { 9 const selectedRows = ref([]); 10 const tableHeaderCheckboxModel = ref(false); 11 const tableHeaderCheckboxIndeterminate = ref(false); 12 13 // Watch for page changes and clear selections 14 // This prevents confusion with checkboxes appearing checked on the new page 15 watch(currentPage, (newPage, oldPage) => { 16 if (newPage !== oldPage) { 17 selectedRows.value = []; 18 tableHeaderCheckboxModel.value = false; 19 tableHeaderCheckboxIndeterminate.value = false; 20 } 21 }); 22 23 const clearSelectedRows = (tableRef) => { 24 if (tableRef) { 25 tableRef.clearSelected(); 26 selectedRows.value = []; 27 tableHeaderCheckboxModel.value = false; 28 tableHeaderCheckboxIndeterminate.value = false; 29 } 30 }; 31 32 const toggleSelectRow = (tableRef, rowIndex) => { 33 if (tableRef && rowIndex !== undefined) { 34 const wasSelected = tableRef.isRowSelected(rowIndex); 35 36 if (wasSelected) { 37 tableRef.unselectRow(rowIndex); 38 } else { 39 tableRef.selectRow(rowIndex); 40 } 41 42 nextTick(() => { 43 onRowSelected(tableRef); 44 }); 45 } 46 }; 47 48 const onRowSelected = (tableRef) => { 49 if (!tableRef) return; 50 51 const allItems = tableRef.filteredItems || tableRef.items || []; 52 const selectedItems = allItems.filter((item, index) => { 53 return tableRef.isRowSelected(index); 54 }); 55 56 selectedRows.value = selectedItems; 57 58 const currentPage = 1; 59 const perPage = allItems.length; 60 const startIndex = (currentPage - 1) * perPage; 61 const endIndex = Math.min(startIndex + perPage, allItems.length); 62 const pageItemsCount = endIndex - startIndex; 63 64 const selectedOnPageCount = selectedItems.filter((item) => 65 allItems 66 .slice(startIndex, endIndex) 67 .some((pageItem) => pageItem === item), 68 ).length; 69 70 if (selectedOnPageCount === 0) { 71 tableHeaderCheckboxIndeterminate.value = false; 72 tableHeaderCheckboxModel.value = false; 73 } else if (selectedOnPageCount === pageItemsCount) { 74 tableHeaderCheckboxIndeterminate.value = false; 75 tableHeaderCheckboxModel.value = true; 76 } else { 77 tableHeaderCheckboxIndeterminate.value = true; 78 tableHeaderCheckboxModel.value = true; 79 } 80 }; 81 82 const onChangeHeaderCheckbox = (tableRef, event) => { 83 /* 84 * Bootstrap Vue Next Migration: 85 * Handle header checkbox to select/deselect all rows on current page. 86 */ 87 if (!tableRef) return; 88 89 const isChecked = 90 typeof event === 'boolean' ? event : event?.target?.checked; 91 92 if (isChecked) { 93 const allItems = tableRef.filteredItems || tableRef.items || []; 94 const endIndex = allItems.length; 95 96 for (let i = 0; i < endIndex; i++) { 97 tableRef.selectRow(i); 98 } 99 } else { 100 tableRef.clearSelected(); 101 selectedRows.value = []; 102 tableHeaderCheckboxModel.value = false; 103 tableHeaderCheckboxIndeterminate.value = false; 104 } 105 106 nextTick(() => { 107 onRowSelected(tableRef); 108 }); 109 }; 110 111 return { 112 selectedRows, 113 tableHeaderCheckboxModel, 114 tableHeaderCheckboxIndeterminate, 115 clearSelectedRows, 116 toggleSelectRow, 117 onRowSelected, 118 onChangeHeaderCheckbox, 119 }; 120} 121