Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(table): Add syncable sort-by and sort-desc props #742

Merged
merged 9 commits into from Jul 28, 2017
128 changes: 74 additions & 54 deletions docs/components/table/README.md
Expand Up @@ -19,8 +19,8 @@ custom rendering, events, and asynchronous data.
</div>
</div>

<div class="justify-content-center row my-1">
<b-pagination size="md" :total-rows="totalRows" :per-page="perPage" v-model="currentPage" />
<div class="my-1">
<b-pagination size="md" align="center" :total-rows="totalRows" :per-page="perPage" v-model="currentPage" />
</div>

<!-- Main table element -->
Expand All @@ -30,6 +30,8 @@ custom rendering, events, and asynchronous data.
:current-page="currentPage"
:per-page="perPage"
:filter="filter"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
@filtered="onFiltered"
>
<template slot="name" scope="row">{{row.value.first}} {{row.value.last}}</template>
Expand All @@ -40,6 +42,10 @@ custom rendering, events, and asynchronous data.
</template>
</b-table>

<p>
Sort By: {{ sortBy || 'n/a' }}, Direction: {{ sortDesc ? 'descending' : 'ascending' }}
</p>

<!-- Details modal -->
<b-modal id="modal1" @hide="resetDetails" ok-only>
<h4 class="my-1 py-1" slot="modal-header">Index: {{ modalDetails.index }}</h4>
Expand All @@ -51,39 +57,25 @@ custom rendering, events, and asynchronous data.

<script>
const items = [
{
isActive: true, age: 40, name: { first: 'Dickerson', last: 'Macdonald' }
}, {
isActive: false, age: 21, name: { first: 'Larsen', last: 'Shaw' }
}, {
_rowVariant: 'success',
isActive: false, age: 9, name: { first: 'Mitzi', last: 'Navarro' }
}, {
isActive: false, age: 89, name: { first: 'Geneva', last: 'Wilson' }
}, {
isActive: true, age: 38, name: { first: 'Jami', last: 'Carney' }
}, {
isActive: false, age: 27, name: { first: 'Essie', last: 'Dunlap' }
}, {
isActive: true, age: 40, name: { first: 'Dickerson', last: 'Macdonald' }
}, {
_cellVariants: { age: 'danger', isActive: 'warning' },
isActive: true, age: 87, name: { first: 'Larsen', last: 'Shaw' }
}, {
isActive: false, age: 26, name: { first: 'Mitzi', last: 'Navarro' }
}, {
isActive: false, age: 22, name: { first: 'Geneva', last: 'Wilson' }
}, {
isActive: true, age: 38, name: { first: 'Jami', last: 'Carney' }
}, {
isActive: false, age: 27, name: { first: 'Essie', last: 'Dunlap' }
}
{ isActive: true, age: 40, name: { first: 'Dickerson', last: 'Macdonald' } },
{ isActive: false, age: 21, name: { first: 'Larsen', last: 'Shaw' } },
{ _rowVariant: 'success',
isActive: false, age: 9, name: { first: 'Mini', last: 'Navarro' } },
{ isActive: false, age: 89, name: { first: 'Geneva', last: 'Wilson' } },
{ isActive: true, age: 38, name: { first: 'Jami', last: 'Carney' } },
{ isActive: false, age: 27, name: { first: 'Essie', last: 'Dunlap' } },
{ isActive: true, age: 40, name: { first: 'Thor', last: 'Macdonald' } },
{ _cellVariants: { age: 'danger', isActive: 'warning' },
isActive: true, age: 87, name: { first: 'Larsen', last: 'Shaw' } },
{ isActive: false, age: 26, name: { first: 'Mitzi', last: 'Navarro' } },
{ isActive: false, age: 22, name: { first: 'Genevive', last: 'Wilson' } },
{ isActive: true, age: 38, name: { first: 'John', last: 'Carney' } },
{ isActive: false, age: 29, name: { first: 'Dick', last: 'Dunlap' } }
];

export default {
data: {
items: items,
totalRows: items.length,
fields: {
name: { label: 'Person Full name', sortable: true },
age: { label: 'Person age', sortable: true, 'class': 'text-center' },
Expand All @@ -92,7 +84,10 @@ export default {
},
currentPage: 1,
perPage: 5,
totalRows: items.length,
pageOptions: [{text:5,value:5},{text:10,value:10},{text:15,value:15}],
sortBy: null,
sortDesc: false,
filter: null,
modalDetails: { index:'', data:'' }
},
Expand All @@ -118,9 +113,10 @@ export default {
<!-- table-1.vue -->
```

### `fields` prop
The `fields` prop is used to display table columns.
Keys are used to extract real value from each row.
### Fields (column definitions)
The `fields` prop is used to display table columns. Keys (i.e. `age` or `name`
as shown below) are used to extract real value from each row.

Example format:
```js
{
Expand All @@ -134,41 +130,46 @@ Example format:
}
}
```

Supported field properties:

| Property | Type | Description
| ---------| ---- | -----------
| `label` | String | Appears in the columns table header (and footer if `foot-clone` is set)
| `label` | String | Appears in the columns table header (and footer if `foot-clone` is set). Defaults to the field's key
| `sortable` | Boolean | Enable sorting on this column
| `variant` | String | Apply contextual class to the `<th>` **and** `<td>` in the column column (`active`, `success`, `info`, `warning`, `danger`)
| `variant` | String | Apply contextual class to the `<th>` **and** `<td>` in the column (`active`, `success`, `info`, `warning`, `danger`)
| `class` | String or Array | Class name (or array of class names) to add to `<th>` **and** `<td>` in the column
| `thClass` | String or Array | Class name (or array of class names) to add to header/footer `<th>` cell
| `tdClass` | String or Array | Class name (or array of class names) to add to data `<td>` cells in the column
| `thStyle` | Object | JavaScript object representing CSS styles you would like to apply to the table field `<th>`

*Field properties, if not present, default to null*

For information on the syntax supported by `thStyle`, see
Notes:
- Field properties, if not present, default to null unless otherwise stated above.
- `thClass` and `tdClass` will not work with classes that are defined in scoped CSS
- For information on the syntax supported by `thStyle`, see
[Class and Style Bindings](https://vuejs.org/v2/guide/class-and-style.html#Binding-Inline-Styles)
in the Vue.js guide.

Any additional properties added to the field objects will be left intact - so you can access
- Any additional properties added to the field objects will be left intact - so you can access
them via the named scoped slots for custom data, header, and footer rendering.

### `items` Prop
### Items (record data)
`items` are real table data record objects in array format. Example format:

```js
[
{
age: 32,
name: 'Cyndi'
},
{
_rowVariant: 'success', // Displays record row green
age: 27,
name: 'Havij'
},
{
_cellVariants: {
age: 'danger', // Displayes cell for field 'age' red
name: 'success' // Displayes cell for field 'name' green
age: 'danger', // Displays cell for field 'age' red
name: 'success' // Displays cell for field 'name' green
},
age: 42,
name: 'Robert'
Expand All @@ -180,8 +181,8 @@ Supported optional item record modifier properties (make sure your field keys do

| Property | Type | Description
| ---------| ---- | -----------
| `_rowVariant` | String | Bootstrap contextual state applied to row (`active`, `success`, `info`, `warning`, `danger`)
| `_cellVariants` | Object | Bootstrap contextual state applied to individual cells. Keyed by field (`active`, `success`, `info`, `warning`, `danger`)
| `_rowVariant` | String | Bootstrap contextual state applied to row (Supported values: `active`, `success`, `info`, `warning`, `danger`)
| `_cellVariants` | Object | Bootstrap contextual state applied to individual cells. Keyed by field (Supported values: `active`, `success`, `info`, `warning`, `danger`)
| `state` | String | **deprecated** in favour of `_rowVariant`

**Note** `state` is deprecated. The property `_rowVariant`, if present in
Expand Down Expand Up @@ -382,12 +383,28 @@ will emit the `filtered` event, passing a single argument which is the complete
items passing the filter routine. Treat this argument as read-only.

### Sorting
As mentioned above in the **fields** section, you can make columns sortable. Clciking on
sortable a column header will sort the column in ascending direction, while clicking
on it again will switch the direction or sorting. Clicking on a non-sortable column
Copy link
Member

@mosinve mosinve Jul 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed a reset by clicking on non-sortable column, because it just set sortBy to null, but parameter sort=null|<sortDesc>still sending to backend API.
On another tought, is may be up to Item provider func to deal with null sort target and remove it from query.
And on third thought, maybe better not expicitly to null sortBy, but reset it to default sortBy, defined at startup. If it not defined, then to null it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although some may want to clear the sort... but you never know. The original table (from before I started working on it) cleared the sort on a non-sortable column.

Some people may want to table to display in the order sent from the server (as not having a null sort by would case b-table to sort the data which is received).

Copy link
Member

@mosinve mosinve Jul 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, i think that this feature should be restored at my variant of <b-table>
But it needs to be reviewed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, we can merge this branch, and i will continue to work on mine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK cool... so everything looks OK in this branch?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmm, Ill make a final test at local Playground doc, though

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK good... The docs example should show the sort key and order under the table, using the .sync modifier.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I could dd a button that says 'clear sort' (which is disabled if sort-by is null) to the example.

Clicking on the button would set sort-by to null, and if sort-by is null then the button could be disabled. Sowing a bit more interactivity with with the table.

will clear the sorting.

You can control which column is pre-sorted and the order of sorting (ascending or
descending). To pre-specify the column to be sorted, set the `sort-by` prop to
the field's key. Set the sort direction by setting `sort-desc` to either `true`
(for descending) or `false` (for ascending, the default).

The props `sort-by` and `sort-desc` can be turned into _two-way_ props by adding the `.sync`
modifier. Your bound variables will then be updated accordingly based on the current sort critera.
See the [Vue docs](http://vuejs.org/v2/guide/components.html#sync-Modifier) for details
on the `.sync` prop modifier

#### Sort-Compare routine
The built-in default `sort-compare` function sorts the specified field `key` based
on the data in the underlying record object. The field value is first stringified
if it is an object, and then sorted.

The default `sort-compare` routine **cannot** sort neither virtual columns, nor
based on the custom rendering of the field data (which is used only for presentation).
The default `sort-compare` routine **cannot** sort virtual columns, nor sort based
on the custom rendering of the field data (which is used only for presentation).
For this reason, you can provide your own custom sort compare routine by passing a
function reference to the prop `sort-compare`.

Expand All @@ -401,14 +418,9 @@ The default sort-compare routine works as follows:
```js
if (typeof a[key] === 'number' && typeof b[key] === 'number') {
// If both compared fields are native numbers
if (a[key] < b[key]) {
return -1;
} else if (a[key] > b[key]) {
return 1;
}
return 0;
return a[key] < b[key] ? -1 : (a[key] > b[key] ? : 1 : 0);
} else {
// Strinify the field data and use String.localeCompare
// Stringify the field data and use String.localeCompare
return toString(a[key]).localeCompare(toString(b[key]), undefined, {
numeric: true
});
Expand Down Expand Up @@ -575,6 +587,14 @@ methods: {
}
```

You can also obtain the current sortBy and sortDesc values by using the `:sort-by.sync` and
`:sort-desc.sync` two-way props respectively (see section **Sorting** above for details).

```html
<b-table :sort-by.sync="mySortBy" :sort-desc.sync="mySortDesc" ...>
</b-table>
```


### Server Side Rendering
Special care must be taken when using server side rendering (SSR) and an `items` provider
Expand Down