Skip to content

Commit 966077d

Browse files
author
Pooya Parsa
committed
[WIP] Better tables
1 parent 930cc09 commit 966077d

File tree

4 files changed

+135
-93
lines changed

4 files changed

+135
-93
lines changed

docs/components/table/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
> For tabular data. Tables support pagination and custom rendering.
44
5-
### `fields`
5+
### Fields
66
Fields prop is used to display table columns.
77
keys are used to extract real value from each raw.
88
Example format:
@@ -17,7 +17,7 @@ age: {
1717
}
1818
```
1919

20-
### `items`
20+
### Items
2121
Items are real table data records. Example format:
2222

2323
```js

lib/components/table.vue

Lines changed: 12 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
:class="[field.sortable?'sorting':null,sortBy===key?'sorting_'+(sortDesc?'desc':'asc'):'',field.class?field.class:null]"
77
v-for="field,key in fields"
88
v-html="field.label"
9+
:key="key"
910
></th>
1011
</tr>
1112
</thead>
1213
<tbody>
13-
<tr v-for="(item,index) in _items" :key="items_key" :class="[item.state?'table-'+item.state:null]">
14+
<tr v-for="(item,index) in _items" :key="item[items_key]" :class="[item.state?'table-'+item.state:null]">
1415
<td v-for="(field,key) in fields" :class="[field.class?field.class:null]">
1516
<slot :name="key" :value="item[key]" :item="item" :index="index">{{item[key]}}</slot>
1617
</td>
@@ -20,42 +21,25 @@
2021
</template>
2122

2223
<script>
23-
import bPagination from './pagination.vue';
24-
25-
const toString = v => {
26-
if (!v) {
27-
return '';
28-
}
29-
30-
if (v instanceof Object) {
31-
return Object.keys(v).map(k => toString(v[k])).join(' ');
32-
}
33-
34-
return String(v);
35-
};
36-
37-
const defaultSortCompare = (a, b, sortBy) => {
38-
return toString(a[sortBy]).localeCompare(toString(b[sortBy]), undefined, {numeric: true});
39-
};
24+
import LocalAdapter from '../utils/local-adapter';
4025
4126
export default {
42-
components: {bPagination},
4327
data() {
4428
return {
4529
sortBy: null,
4630
sortDesc: true
4731
};
4832
},
49-
5033
props: {
5134
items: {
52-
type: Array,
53-
default: () => []
35+
type: Array
5436
},
5537
fields: {
38+
type: Object
39+
},
40+
adapter: {
5641
type: Object,
57-
default: () => {
58-
}
42+
default: () => new LocalAdapter(this)
5943
},
6044
striped: {
6145
type: Boolean,
@@ -72,90 +56,27 @@
7256
items_key: {
7357
type: String,
7458
default: null
75-
},
76-
currentPage: {
77-
type: Number,
78-
default: 1
79-
},
80-
filter: {
81-
type: [String, RegExp, Function],
82-
default: null
83-
},
84-
sortCompare: {
85-
type: Function,
86-
default: null
87-
},
88-
itemsProvider: {
89-
type: Function,
90-
default: null
91-
},
92-
value: {
93-
type: Array,
94-
default: () => []
9559
}
9660
},
9761
9862
computed: {
9963
_items() {
100-
if (!this.items) {
101-
return [];
102-
}
103-
104-
if (this.itemsProvider) {
105-
return this.itemsProvider(this);
106-
}
107-
108-
let items = this.items;
109-
110-
// Apply filter
111-
if (this.filter) {
112-
if (this.filter instanceof Function) {
113-
items = items.filter(this.filter);
114-
} else {
115-
let regex;
116-
if (this.filter instanceof RegExp) {
117-
regex = this.filter;
118-
} else {
119-
regex = new RegExp('.*' + this.filter + '.*', 'ig');
120-
}
121-
items = items.filter(item => {
122-
const test = regex.test(toString(item));
123-
regex.lastIndex = 0;
124-
return test;
125-
});
126-
}
127-
}
128-
129-
// Apply Sort
130-
const sortCompare = this.sortCompare || defaultSortCompare;
131-
if (this.sortBy) {
132-
items = items.sort((a, b) => {
133-
const r = sortCompare(a, b, this.sortBy);
134-
return this.sortDesc ? r : r * -1;
135-
});
136-
}
137-
64+
const items = this.adapter.items();
13865
this.$emit('input', items);
139-
140-
// Apply pagination
141-
if (this.perPage) {
142-
items = items.slice((this.currentPage - 1) * this.perPage, this.currentPage * this.perPage);
143-
}
144-
return items;
14566
}
14667
},
14768
methods: {
14869
headClick(field, key) {
14970
if (!field.sortable) {
150-
this.sortBy = null;
71+
this.adapter.setSortBy(null);
15172
return;
15273
}
15374
15475
if (key === this.sortBy) {
155-
this.sortDesc = !this.sortDesc;
76+
this.adapter.toggleSortDesc();
15677
}
15778
158-
this.sortBy = key;
79+
this.adapter.setSortBy(key);
15980
}
16081
}
16182
};

lib/utils/base-adapter.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
export default class BaseAdapter {
2+
/**
3+
* Base Table adapter
4+
* @constructor
5+
*/
6+
constructor(options) {
7+
this.options = options;
8+
9+
this.sortDesc = false;
10+
this.sortBy = null;
11+
this.filter = null;
12+
}
13+
14+
getItems() {
15+
return [];
16+
}
17+
18+
/**
19+
* [Util] Returns string representation of a row
20+
* @param v
21+
* @returns String
22+
*/
23+
static stringValue(v) {
24+
if (!v) {
25+
return '';
26+
}
27+
28+
if (v instanceof Object) {
29+
return Object.keys(v).map(k => this.stringValue(v[k])).join(' ');
30+
}
31+
32+
return String(v);
33+
}
34+
35+
/**
36+
* [Util] Compare rows a and b
37+
* @param a
38+
* @param b
39+
* @returns {number}
40+
*/
41+
static sortCompare(a, b) {
42+
return this.stringValue(a).localeCompare(this.stringValue(b), undefined, {numeric: true});
43+
}
44+
45+
/**
46+
* [Util] Applies regex filter
47+
* @param items
48+
* @param regex
49+
*/
50+
static regexFilter(items, regex) {
51+
return items.filter(item => {
52+
const test = regex.test(toString(item));
53+
regex.lastIndex = 0;
54+
return test;
55+
});
56+
}
57+
58+
/**
59+
* [Util] Applies general filtering
60+
* @param items
61+
*/
62+
filterItems(items) {
63+
if (!this.filter) {
64+
return items;
65+
}
66+
67+
if (this.filter instanceof RegExp) {
68+
return this.regexFilter(items, this.filter);
69+
}
70+
71+
const regex = new RegExp('.*' + this.filter + '.*', 'ig');
72+
return this.regexFilter(items, regex);
73+
}
74+
75+
/**
76+
* Set SortBy field
77+
* @param sortBy
78+
*/
79+
setSortBy(sortBy) {
80+
this.sortBy = sortBy;
81+
}
82+
83+
/**
84+
* toggle Sort Desc
85+
*/
86+
toggleSortDesc() {
87+
this.sortDesc = !this.sortDesc;
88+
}
89+
}
90+

lib/utils/local-adapter.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import BaseAdapter from './base-adapter';
2+
3+
export default class LocalAdapter extends BaseAdapter {
4+
/**
5+
* Table adapter with all data in memory
6+
* @constructor
7+
*/
8+
constructor(options) {
9+
super(options);
10+
}
11+
12+
getItems() {
13+
// Apply filter
14+
let items = this.filterItems(this.items);
15+
16+
// Apply Sort
17+
if (this.sortBy) {
18+
items = items.sort((a, b) => this.sortCompare(a[this.sortBy], b[this.sortBy]) * (this.sortDesc ? 1 : -1));
19+
}
20+
21+
// Apply pagination
22+
if (this.perPage) {
23+
items = items.slice((this.currentPage - 1) * this.perPage, this.currentPage * this.perPage);
24+
}
25+
26+
return items;
27+
}
28+
29+
30+
}
31+

0 commit comments

Comments
 (0)