summaryrefslogtreecommitdiff
path: root/src/components/Composables/useTableSelection.js
blob: f0a52600c6d6361bae1dcb2c8b430ff41ec1fcd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/**
 * 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,
  };
}