diff --git a/src/components/DataTable.vue b/src/components/DataTable.vue index e51b2ab..fd95630 100644 --- a/src/components/DataTable.vue +++ b/src/components/DataTable.vue @@ -369,6 +369,8 @@ const { themeColor, rowsOfPageSeparatorMessage, showIndexSymbol, + itemsExpanded, + itemsKey, preventContextMenuRow } = toRefs(props); @@ -411,7 +413,8 @@ const emits = defineEmits([ 'update:serverOptions', 'updatePageItems', 'updateTotalItems', - 'selectAll' + 'selectAll', + 'update:itemsExpanded', ]); const isMultipleSelectable = computed((): boolean => itemsSelected.value !== null); @@ -485,6 +488,7 @@ const { serverItemsLength, multiSort, emits, + itemsKey, ); const { @@ -521,6 +525,7 @@ const { showIndex, totalItems, totalItemsLength, + itemsKey, ); const prevPageEndIndex = computed(() => { @@ -536,6 +541,8 @@ const { pageItems, prevPageEndIndex, emits, + itemsExpanded, + itemsKey, ); const { diff --git a/src/hooks/useExpandableRow.ts b/src/hooks/useExpandableRow.ts index 38bec72..97744e7 100644 --- a/src/hooks/useExpandableRow.ts +++ b/src/hooks/useExpandableRow.ts @@ -1,11 +1,14 @@ -import { ref, Ref, ComputedRef } from 'vue'; -import type { Item } from '../types/main'; +import { ref, Ref, ComputedRef, watchEffect } from 'vue'; +import type { Item, ItemKey } from '../types/main'; import type { EmitsEventName } from '../types/internal'; +import { getItemIndex } from '../utils'; export default function useExpandableRow( items: Ref, prevPageEndIndex: ComputedRef, emits: (event: EmitsEventName, ...args: any[]) => void, + itemsExpanded: Ref, + itemsKey: Ref ) { const expandingItemIndexList = ref([]); @@ -14,10 +17,12 @@ export default function useExpandableRow( const index = expandingItemIndexList.value.indexOf(expandingItemIndex); if (index !== -1) { expandingItemIndexList.value.splice(index, 1); + emitItemsExpanded(); } else { - const currentPageExpandIndex = items.value.findIndex((item) => JSON.stringify(item) === JSON.stringify(expandingItem)); + const currentPageExpandIndex = getItemIndex(items.value, expandingItem, itemsKey.value) emits('expandRow', prevPageEndIndex.value + currentPageExpandIndex, expandingItem); expandingItemIndexList.value.push(prevPageEndIndex.value + currentPageExpandIndex); + emitItemsExpanded(); } }; @@ -25,6 +30,22 @@ export default function useExpandableRow( expandingItemIndexList.value = []; }; + watchEffect(() => { + const indexList = itemsExpanded.value.reduce((itemsExpandedIndex, expandedItem) => { + const index = getItemIndex(items.value, expandedItem, itemsKey.value) + if (index !== -1) { + itemsExpandedIndex.push(index + prevPageEndIndex.value) + } + return itemsExpandedIndex + }, []) + expandingItemIndexList.value = indexList + }) + + + function emitItemsExpanded() { + emits('update:itemsExpanded', expandingItemIndexList.value.map(index => items.value[index - prevPageEndIndex.value])) + } + return { expandingItemIndexList, updateExpandingItemIndexList, diff --git a/src/hooks/usePageItems.ts b/src/hooks/usePageItems.ts index dab08ca..84010cf 100644 --- a/src/hooks/usePageItems.ts +++ b/src/hooks/usePageItems.ts @@ -1,8 +1,9 @@ import { Ref, computed, ComputedRef, WritableComputedRef, } from 'vue'; -import type { Item } from '../types/main'; +import type { Item, ItemKey } from '../types/main'; import type { MultipleSelectStatus } from '../types/internal'; +import { areItemsEqual, getItemIndex } from '../utils'; export default function usePageItems( currentPaginationNumber: Ref, @@ -14,6 +15,7 @@ export default function usePageItems( showIndex: Ref, totalItems: ComputedRef, totalItemsLength: ComputedRef, + itemsKey: Ref ) { const currentPageFirstIndex = computed((): number => (currentPaginationNumber.value - 1) * rowsPerPageRef.value + 1); @@ -45,21 +47,13 @@ export default function usePageItems( if (selectItemsComputed.value.length === 0) { return 'noneSelected'; } - const isNoneSelected = selectItemsComputed.value.every((itemSelected) => { - if (totalItems.value.findIndex((item) => JSON.stringify(itemSelected) === JSON.stringify(item)) !== -1) { - return false; - } - return true; - }); + const isNoneSelected = selectItemsComputed.value + .every((itemSelected) => getItemIndex(totalItems.value, itemSelected, itemsKey.value) === -1); if (isNoneSelected) return 'noneSelected'; if (selectItemsComputed.value.length === totalItems.value.length) { - const isAllSelected = selectItemsComputed.value.every((itemSelected) => { - if (totalItems.value.findIndex((item) => JSON.stringify(itemSelected) === JSON.stringify(item)) === -1) { - return false; - } - return true; - }); + const isAllSelected = selectItemsComputed.value + .every((itemSelected) => (getItemIndex(totalItems.value, itemSelected, itemsKey.value) !== -1)); return isAllSelected ? 'allSelected' : 'partSelected'; } @@ -79,7 +73,7 @@ export default function usePageItems( const isSelected = selectItemsComputed.value.findIndex((selectItem) => { const itemDeepCloned = { ...item }; delete itemDeepCloned.index; - return JSON.stringify(selectItem) === JSON.stringify(itemDeepCloned); + return areItemsEqual(selectItem, itemDeepCloned, itemsKey.value) }) !== -1; return { checkbox: isSelected, ...item }; }); diff --git a/src/hooks/useTotalItems.ts b/src/hooks/useTotalItems.ts index 5c2cc41..261166a 100644 --- a/src/hooks/useTotalItems.ts +++ b/src/hooks/useTotalItems.ts @@ -1,9 +1,9 @@ import { Ref, computed, ComputedRef, watch, } from 'vue'; -import type { Item, FilterOption } from '../types/main'; +import type { Item, FilterOption, ItemKey } from '../types/main'; import type { ClientSortOptions, EmitsEventName } from '../types/internal'; -import { getItemValue } from '../utils'; +import { areItemsEqual, getItemValue } from '../utils'; export default function useTotalItems( clientSortOptions: Ref, @@ -16,6 +16,7 @@ export default function useTotalItems( serverItemsLength: Ref, multiSort: Ref, emits: (event: EmitsEventName, ...args: any[]) => void, + itemsKey: Ref ) { const generateSearchingTarget = (item: Item): string => { if (typeof searchField.value === 'string' && searchField.value !== '') return getItemValue(searchField.value, item); @@ -152,8 +153,8 @@ export default function useTotalItems( selectItemsComputed.value = selectItemsArr; emits('selectRow', item); } else { - selectItemsComputed.value = selectItemsComputed.value.filter((selectedItem) => JSON.stringify(selectedItem) - !== JSON.stringify(item)); + selectItemsComputed.value = selectItemsComputed.value + .filter((selectedItem) => !areItemsEqual(selectedItem, item, itemsKey.value)); emits('deselectRow', item); } }; diff --git a/src/modes/Client.vue b/src/modes/Client.vue index bdbe259..1552038 100644 --- a/src/modes/Client.vue +++ b/src/modes/Client.vue @@ -9,6 +9,7 @@ search value:
+