Skip to content

Commit cc663da

Browse files
committed
feat(DsfrDataTable): ✨ permet de sélectionner toutes lignes
1 parent 89ff17f commit cc663da

File tree

3 files changed

+117
-45
lines changed

3 files changed

+117
-45
lines changed

src/components/DsfrDataTable/DsfrDataTable.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ export type DsfrDataTableProps = {
2020
paginationOptions?: number[]
2121
currentPage?: number
2222
rowsPerPage?: number
23+
bottomActionBarClass?: string | Record<string, boolean> | Array<string | Record<string, boolean>>
24+
paginationWrapperClass?: string | Record<string, boolean> | Array<string | Record<string, boolean>>
2325
}

src/components/DsfrDataTable/DsfrDataTable.vue

Lines changed: 102 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts" setup>
2-
import { computed } from 'vue'
2+
import { computed, ref } from 'vue'
33
44
import { getRandomId } from '@/utils/random-utils'
55
import DsfrPagination, { type Page } from '../DsfrPagination/DsfrPagination.vue'
@@ -11,6 +11,7 @@ const props = withDefaults(defineProps<DsfrDataTableProps>(), {
1111
bottomActionsRow: () => [],
1212
currentPage: 0,
1313
rowsPerPage: 10,
14+
rowKey: 0,
1415
paginationOptions: () => [
1516
5,
1617
10,
@@ -22,7 +23,7 @@ const emit = defineEmits<{
2223
'update:current-page': [page: number]
2324
}>()
2425
25-
const selection = defineModel<string[]>('selection')
26+
const selection = defineModel<string[]>('selection', { default: [] })
2627
const rowsPerPage = defineModel<number>('rowsPerPage', { default: 10 })
2728
const currentPage = defineModel<number>('currentPage', { default: 1 })
2829
const pageCount = computed(() => Math.ceil(props.rows.length / rowsPerPage.value))
@@ -52,6 +53,24 @@ const finalRows = computed(() => {
5253
5354
return rows
5455
})
56+
57+
function selectAll (bool: boolean) {
58+
if (bool) {
59+
const keyIndex = props.headersRow.findIndex(header => (header as DsfrDataTableHeaderCellObject).key ?? header)
60+
selection.value = finalRows.value.map(row => row[keyIndex] as string)
61+
}
62+
selection.value!.length = 0
63+
}
64+
const wholeSelection = ref(false)
65+
function checkSelection () {
66+
wholeSelection.value = selection.value.length === finalRows.value.length
67+
}
68+
69+
function onPaginationOptionsChange () {
70+
emit('update:current-page', 0)
71+
wholeSelection.value = false
72+
selection.value.length = 0
73+
}
5574
</script>
5675

5776
<template>
@@ -72,7 +91,21 @@ const finalRows = computed(() => {
7291
class="fr-cell--fixed"
7392
role="columnheader"
7493
>
75-
<span class="fr-sr-only">Sélectionner</span>
94+
<div class="fr-checkbox-group fr-checkbox-group--sm">
95+
<!-- @vue-expect-error TS2538 -->
96+
<input
97+
:id="`table-select--${id}-all`"
98+
:checked="wholeSelection"
99+
type="checkbox"
100+
@input="selectAll($event.target.checked)"
101+
>
102+
<label
103+
class="fr-label"
104+
:for="`table-select--${id}-all`"
105+
>
106+
Sélectionner tout
107+
</label>
108+
</div>
76109
</th>
77110
<th
78111
v-for="header of headersRow"
@@ -103,14 +136,15 @@ const finalRows = computed(() => {
103136
<div class="fr-checkbox-group fr-checkbox-group--sm">
104137
<!-- @vue-expect-error TS2538 -->
105138
<input
106-
id="table-select-checkbox-7748--0"
139+
:id="`row-select-${id}-${idx}`"
107140
v-model="selection"
108-
:value="row[rowKey] ?? `row-${idx}`"
141+
:value="rows[idx][rowKey] ?? `row-${idx}`"
109142
type="checkbox"
143+
@change="checkSelection()"
110144
>
111145
<label
112146
class="fr-label"
113-
for="table-select-checkbox-7748--0"
147+
:for="`row-select-${id}-${idx}`"
114148
>
115149
Sélectionner la ligne {{ idx + 1 }}
116150
</label>
@@ -141,51 +175,76 @@ const finalRows = computed(() => {
141175
</div>
142176
</div>
143177
</div>
144-
<slot name="pagination">
145-
<template
146-
v-if="pagination"
147-
>
148-
<div class="flex">
149-
<div class="fr-select-group flex">
150-
<label class="fr-label">Résultats par page : </label>
151-
<select
152-
v-model="rowsPerPage"
153-
class="fr-select"
154-
@change="emit('update:current-page', 0)"
155-
>
156-
<option
157-
value=""
158-
:selected="!paginationOptions.includes(rowsPerPage)"
159-
disabled="true"
160-
hidden="hidden"
178+
<div
179+
:class="bottomActionBarClass"
180+
>
181+
<slot name="pagination">
182+
<template
183+
v-if="pagination && !$slots.pagination"
184+
>
185+
<div
186+
class="flex justify-between items-center"
187+
:class="paginationWrapperClass"
188+
>
189+
<div class="flex gap-2 items-center">
190+
<label
191+
class="fr-label"
192+
for="pagination-options"
161193
>
162-
Sélectionner une option
163-
</option>
164-
<option
165-
v-for="(option, idx) in paginationOptions"
166-
:key="idx"
167-
:value="option"
168-
:selected="+option === rowsPerPage"
194+
Résultats par page :
195+
</label>
196+
<select
197+
id="pagination-options"
198+
v-model="rowsPerPage"
199+
class="fr-select"
200+
@change="onPaginationOptionsChange()"
169201
>
170-
{{ option }}
171-
</option>
172-
</select>
173-
</div>
174-
<div class="flex ml-1">
175-
<span class="self-center">Page {{ currentPage + 1 }} sur {{ pageCount }}</span>
202+
<option
203+
value=""
204+
:selected="!paginationOptions.includes(rowsPerPage)"
205+
disabled="true"
206+
hidden="hidden"
207+
>
208+
Sélectionner une option
209+
</option>
210+
<option
211+
v-for="(option, idx) in paginationOptions"
212+
:key="idx"
213+
:value="option"
214+
:selected="+option === rowsPerPage"
215+
>
216+
{{ option }}
217+
</option>
218+
</select>
219+
</div>
220+
<div class="flex ml-1">
221+
<span class="self-center">Page {{ currentPage + 1 }} sur {{ pageCount }}</span>
222+
</div>
223+
<DsfrPagination
224+
v-model:current-page="currentPage"
225+
:pages="pages"
226+
/>
176227
</div>
177-
<DsfrPagination
178-
v-model:current-page="currentPage"
179-
:pages="pages"
180-
/>
181-
</div>
182-
</template>
183-
</slot>
228+
</template>
229+
</slot>
230+
</div>
184231
</div>
185232
</template>
186233

187234
<style scoped>
188235
.flex {
189236
display: flex;
190237
}
238+
.justify-between {
239+
justify-content: space-between;
240+
}
241+
.items-center {
242+
align-items: center;
243+
}
244+
.gap-2 {
245+
gap: 0.5rem;
246+
}
247+
:deep(.fr-pagination__link) {
248+
margin-bottom: 0 !important;
249+
}
191250
</style>

src/components/DsfrDataTable/docs-demo/DsfrDataTableDemoPlusComplexe.vue

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,20 @@ const currentPage = ref<number>(0)
3434
</script>
3535

3636
<template>
37-
<div class="fr-container fr-my-2v">
37+
<div class="fr-container fr-my-2v w-[800px]">
3838
<DsfrDataTable
3939
v-model:selection="selection"
4040
v-model:current-page="currentPage"
4141
:headers-row="headers"
4242
:rows="rows"
4343
selectable-rows
44-
:row-key="0"
44+
row-key="id"
4545
title="Titre du tableau (caption)"
4646
pagination
4747
:rows-per-page="2"
4848
:pagination-options="[1, 2, 3]"
49+
bottom-action-bar-class="bottom-action-bar-class"
50+
pagination-wrapper-class="pagination-wrapper-class"
4951
>
5052
<template #header="{ key, label }">
5153
<div @click="click($event, key)">
@@ -65,3 +67,12 @@ const currentPage = ref<number>(0)
6567
IDs sélectionnées : {{ selection }}
6668
</div>
6769
</template>
70+
71+
<style scoped>
72+
:deep(.bottom-action-bar-class) {
73+
width: 860px;
74+
}
75+
:deep(.pagination-wrapper-class) {
76+
width: 860px;
77+
}
78+
</style>

0 commit comments

Comments
 (0)