Skip to content

Commit 6be840c

Browse files
committed
add options to simple datatable
1 parent 245d3b3 commit 6be840c

File tree

7 files changed

+203
-20
lines changed

7 files changed

+203
-20
lines changed

src/App.vue

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,33 @@ export default defineComponent({
1919
color: #2c3e50;
2020
margin-top: 60px;
2121
}
22+
23+
.container {
24+
width: 600px;
25+
margin: auto;
26+
}
27+
.row {
28+
display: flex;
29+
flex-wrap: wrap;
30+
flex: 1 1 auto;
31+
}
32+
.col {
33+
display: flex;
34+
padding: 8px;
35+
}
36+
.width-40 {
37+
width: 40%;
38+
}
39+
.mt-8 {
40+
margin-top: 32px;
41+
}
42+
.mt-4 {
43+
margin-top: 16px;
44+
}
45+
.border-right {
46+
border-right: 1px solid;
47+
}
48+
.border-bottom {
49+
border-bottom: 1px solid;
50+
}
2251
</style>

src/examples/BaseOrdering.vue

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<template>
2+
<button @click="emitOrdering">{{buttonText}}</button>
3+
</template>
4+
5+
<script>
6+
export default {
7+
name: "BaseOrdering",
8+
props: {
9+
value: {
10+
type: Array,
11+
required: true
12+
},
13+
field: {
14+
type: String,
15+
reaquired: true
16+
},
17+
},
18+
data() {
19+
return {};
20+
},
21+
computed: {
22+
valueField() {
23+
if (this.value[0] && this.value[0].startsWith("-")) {
24+
return this.value[0].substring(1);
25+
}
26+
return this.value[0];
27+
},
28+
isDesc() {
29+
return this.valueField === this.field && this.value[0].startsWith("-");
30+
},
31+
isAsc() {
32+
return this.valueField === this.field && !this.value[0].startsWith("-");
33+
},
34+
isEmptyString() {
35+
return this.valueField !== this.field;
36+
},
37+
buttonText() {
38+
if (this.isEmptyString) {
39+
return "Order Asc"
40+
} else if (this.isAsc) {
41+
return "Order Desc"
42+
}
43+
return "Cancel Order"
44+
}
45+
},
46+
methods: {
47+
emitOrdering() {
48+
let emitValue = [];
49+
if (this.isEmptyString) {
50+
emitValue = [this.field];
51+
} else if (this.isAsc) {
52+
emitValue = [`-${this.field}`];
53+
}
54+
// if IsAsc return null so okay
55+
return this.$emit("input", emitValue);
56+
}
57+
}
58+
};
59+
</script>

src/examples/HelloWorld.vue

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<template>
2-
<div class="hello">
2+
<div class="container">
33
<h1>{{ msg }}</h1>
4-
<h3>test</h3>
4+
<h3>Test Vue Datatable Url Sync</h3>
55

6-
{{form}}
6+
<div class="row mt-8">
7+
<label for="search">Search: </label>
8+
<input id="search" v-model="form.search" />
9+
</div>
710

8-
<input v-model="form.search" />
9-
10-
<SimpleDatatable :items="items" />
11+
<SimpleDatatable v-model:options="options" :items="items" :headers="['id', 'title']" />
1112

1213
</div>
1314
</template>
@@ -30,18 +31,23 @@ export default defineComponent({
3031
const form = ref({
3132
search: ""
3233
})
33-
const options = ref({})
34+
const options = ref({
35+
page: 1,
36+
page_size: 10,
37+
ordering: []
38+
})
3439
const items = ref<any>([])
3540
3641
const fetchDatas = (queryParams: string, queryAsObject: Object) => {
37-
console.log("icicci", queryParams, queryAsObject)
42+
console.log("to remove after", queryParams, queryAsObject)
3843
items.value = fakeData
3944
}
4045
4146
useDatatableUrlSync(form, fetchDatas, options)
4247
4348
return {
4449
form,
50+
options,
4551
items
4652
}
4753
}

src/examples/SimpleDatatable.vue

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,91 @@
11
<template>
2-
<div>
3-
Datatable
4-
</div>
5-
<div>
6-
<div v-for="item in items" :key="item[itemKey]">
7-
<div v-for="(value, key) in item" :key="key">
8-
{{key}}: {{value}}
2+
<div class="container">
3+
<div class="mt-8">
4+
Datatable
5+
</div>
6+
<div class="mt-8 row">
7+
<div v-for="header in headers" :key="header" class="col width-40 border-right border-bottom">
8+
<p>{{header}}</p>
9+
<BaseOrdering :field="header" :value="options.ordering" @input="emitOptions('ordering', $event)" />
10+
</div>
11+
</div>
12+
<div v-for="item in currentItems" :key="item[itemKey]" class="row">
13+
<div v-for="(value, key) in item" :key="key" class="col width-40 border-right">
14+
<p>{{value}}</p>
15+
</div>
16+
</div>
17+
<div class="mt-4 row">
18+
<div class="col width-40">
19+
<label>Item per page: </label>
20+
<select :modelValue="options.page_size" @change="emitOptions('page_size', parseInt($event.target.value))">
21+
<option v-for="itemNumber in [5, 10, 20]" :key="itemNumber" :selected="options.page_size === itemNumber" :value="itemNumber">{{itemNumber}}</option>
22+
</select>
23+
</div>
24+
25+
<div class="col width-40">
26+
<button v-if="options.page > 1" @click="emitOptions('page', options.page-1)">Prev. page</button>
27+
<button v-if="lastVisibleIndex < items.length" @click="emitOptions('page', options.page+1)">Next page</button>
928
</div>
1029
</div>
1130
</div>
1231
</template>
1332

1433
<script>
34+
import BaseOrdering from "./BaseOrdering";
35+
1536
export default {
1637
name: "SimpleDatatable",
38+
components: {
39+
BaseOrdering
40+
},
1741
props: {
1842
items: {
1943
type: Array,
2044
default: () => []
2145
},
46+
headers: {
47+
type: Array,
48+
default: () => []
49+
},
2250
itemKey: {
2351
type: String,
2452
default: "id"
53+
},
54+
options: {
55+
type: Object,
56+
default: () => ({
57+
page: 1,
58+
page_size: 10,
59+
ordering: []
60+
})
61+
}
62+
},
63+
computed: {
64+
firstVisibleIndex() {
65+
return ((this.options.page ?? 1) - 1) * this.options.page_size ?? 10;
66+
},
67+
lastVisibleIndex() {
68+
return (this.options.page ?? 1) * this.options.page_size ?? 10;
69+
},
70+
currentItems() {
71+
console.log(this.firstVisibleIndex, this.lastVisibleIndex)
72+
if(this.lastVisibleIndex > this.items.length) {
73+
return this.items.slice(this.firstVisibleIndex)
74+
}
75+
return this.items.slice(this.firstVisibleIndex, this.lastVisibleIndex)
76+
}
77+
},
78+
methods: {
79+
emitOptions(optionKey, value) {
80+
const newOptions = {
81+
...this.options,
82+
[optionKey]: value
83+
}
84+
this.$emit("update:options", newOptions)
2585
}
2686
}
2787
}
2888
</script>
2989
3090
<style>
31-
3291
</style>

src/examples/data.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,20 @@ export default [
3535
id: "9",
3636
title: "test9"
3737
},
38+
{
39+
id: "10",
40+
title: "test10"
41+
},
42+
{
43+
id: "11",
44+
title: "test11"
45+
},
46+
{
47+
id: "12",
48+
title: "test12"
49+
},
50+
{
51+
id: "13",
52+
title: "test13"
53+
},
3854
]

src/lib-components/useDatatableUrlSync.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
import cloneDeep from "lodash.clonedeep";
1010
import isEqual from "lodash.isequal";
1111

12-
import { ref, watch } from 'vue'
12+
import { ref, watch, nextTick } from 'vue'
1313
import { useRoute, useRouter } from 'vue-router'
1414
import {GenericDictionnary, VDUSConfiguration} from "./utils/VDUSTypes"
1515

@@ -18,7 +18,7 @@ DOC here on params and return value
1818
*/
1919
export default function useDatatableUrlSync(form: GenericDictionnary, fetchDatas: Function, options: GenericDictionnary, formSchema?: GenericDictionnary, initializeForm?: Function, configurations?:VDUSConfiguration) {
2020

21-
// Set configurations
21+
// ----------------------------- DEFAULTING PARAMS ------------------------------
2222
configurations = {
2323
// use a prefix to differentiate possible same name if two component use the same mixin
2424
prefix: "",
@@ -30,8 +30,14 @@ export default function useDatatableUrlSync(form: GenericDictionnary, fetchDatas
3030
extraQueryParams: {},
3131
...configurations || {}
3232
}
33+
formSchema = {
34+
page: { type: "integer", default: 1 },
35+
page_size: { type: "integer", default: 10 },
36+
ordering: { type: "arrayString", default: [] },
37+
...formSchema
38+
}
3339

34-
// data
40+
// ----------------------------- DATA ------------------------------
3541
const route = useRoute();
3642
const router = useRouter()
3743

@@ -49,11 +55,17 @@ export default function useDatatableUrlSync(form: GenericDictionnary, fetchDatas
4955
localQuery = triggerSearchIfNeeded(isFilter, getDatas);
5056
}, configurations?.debounceTime || 0);
5157

52-
58+
// ----------------------------- WATCH ------------------------------
5359
watch(form, () => {
5460
debounceSearch(true);
5561
}, { deep: true })
5662

63+
watch(options, () => {
64+
nextTick(() => {
65+
localQuery = triggerSearchIfNeeded(false, getDatas);
66+
});
67+
}, { deep: true })
68+
5769

5870

5971
// ----------------------------- METHODS ------------------------------

src/lib-components/utils/listPaginatedTools.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@ function readFormAndOptionsFromLocalQuery(
9191
schema?: GenericDictionnary,
9292
removedParam: Array<string> = []
9393
): {newOptions: GenericDictionnary, newForm: GenericDictionnary} {
94+
9495
let newOptions: GenericDictionnary = {};
9596
let newForm: GenericDictionnary = {};
97+
9698
for (let param in query) {
9799
if (typeof form[param] !== "undefined") {
98100
newForm[param] = convertParamIfTypeInSchema(query, param, schema);

0 commit comments

Comments
 (0)