1# Table 2 3All tables in the application are using the 4[BoostrapVue table component](https://bootstrap-vue.org/docs/components/table). 5 6To use the component, include the `<b-table>` tag in the template. The component 7is registered globally so does not need to be imported in each SFC. 8 9## Basic table 10 11There are a few required properties to maintain consistency across the 12application. The full list of options can be viewed on the 13[Bootstrap-vue table component's documentation page](https://bootstrap-vue.org/docs/components/table#comp-ref-b-table-props). 14 15### Required properties 16 17- `items` - renders table items 18- `fields` - renders table header 19- `hover` - enables table row hover state 20- `responsive` or `stacked` - makes the table responsive (enables horizontal 21 scrolling or stacked view) at the defined breakpoint 22- `show-empty` _(required if table data is generated dynamically)_ - shows an 23 empty message if there are no items in the table 24- `empty-text` _(required if table data is generated dynamically)_ - the 25 translated empty message 26 27 28 30 31```vue 32<template> 33 <b-table 34 hover 35 show-empty 36 responsive="md" 37 :items="items" 38 :fields="fields" 39 :empty-text="$t('global.table.emptyMessage')" 40 /> 41</template> 42 43<script> 44export default { 45 data() { 46 items: [ 47 { 48 name: 'Babe', 49 age: '3 years', 50 color: 'white, orange, grey' 51 }, 52 { 53 name: 'Grey Boy', 54 age: '4 months', 55 color: 'grey' 56 }, 57 ], 58 fields: [ 59 { 60 key: 'name', 61 label: this.$t('table.name') //translated label 62 }, 63 { 64 key: 'age', 65 label: this.$t('table.age') //translated label 66 }, 67 { 68 key: 'color', 69 label: this.$t('table.color') // translated label 70 } 71 ] 72 } 73} 74</script> 75``` 76 77## Sort 78 79To enable table sort, include `sortable: true` in the fields array for sortable 80columns and add the following props to the `<b-table>` component: 81 82- `sort-by` 83- `no-sort-reset` 84- `sort-icon-left` 85 86 87 88```vue 89<template> 90 <b-table 91 hover 92 no-sort-reset 93 sort-icon-left 94 sort-by="rank" 95 responsive="md" 96 :items="items" 97 :fields="fields" 98 /> 99</template> 100<script> 101export default { 102 data() { 103 return { 104 items: [...], 105 fields: [ 106 { 107 key: 'name', 108 label: 'Name', //should be translated 109 sortable: true 110 }, 111 { 112 key: 'rank', 113 label: 'Rank', //should be translated 114 sortable: true 115 }, 116 { 117 key: 'description', 118 label: 'Description', //should be translated 119 sortable: false 120 } 121 ] 122 } 123 } 124} 125</script> 126``` 127 128## Expandable rows 129 130To add an expandable row in the table, add a column for the expand button in the 131fields array. Include the tdClass `table-row-expand` to ensure icon rotation is 132handled. Use the built in 133[cell slot](https://bootstrap-vue.org/docs/components/table#comp-ref-b-table-slots) 134to target the expand button column and add a button with the chevron icon. 135 136Include the 137[TableRowExpandMixin](https://github.com/openbmc/webui-vue/blob/master/src/components/Mixins/TableRowExpandMixin.js). 138The mixin contains the dynamic `aria-label` and `title` attribute values that 139need to be included with the expand button. The `toggleRowDetails` method should 140be the button's click event callback. Be sure to pass the `row` object to the 141function. 142 143Use the 144[row-details slot](https://bootstrap-vue.org/docs/components/table#comp-ref-b-table-slots) 145to format the expanded row content. The slot has access to the row `item` 146property. 147 148### Summary 149 1501. Add a column for the expansion row button with the tdClass, 151 `table-row-expand` 1522. Include the `TableRowExpandMixin` to handle the dynamic aria label, title, 153 and row expansion toggling 1543. Use the `#cell` slot to target the expandable row column and add the button 155 with accessible markup and click handler 1564. Use the `#row-details` slot to format expanded row content 157 158 159 160```vue 161<template> 162 <b-table hover responsive="md" :items="items" :fields="fields"> 163 <template #cell(expandRow)="row"> 164 <b-button 165 variant="link" 166 :aria-label="expandRowLabel" 167 :title="expandRowLabel" 168 @click="toggleRowDetails(row)" 169 > 170 <icon-chevron /> 171 </b-button> 172 </template> 173 <template #row-details="row"> 174 <h3>Expanded row details</h3> 175 {{ row.item }} 176 </template> 177 </b-table> 178</template> 179<script> 180import IconChevron from '@carbon/icons-vue/es/chevron--down/20'; 181import TableRowExpandMixin, { expandRowLabel } from '@/components/Mixins/TableRowExpandMixin'; 182 183export default { 184 components: { IconChevron }, 185 mixins: [ TableRowExpandMixin ], 186 data() { 187 return { 188 items: [...], 189 fields: [ 190 { 191 key: 'expandRow', 192 label: '', 193 tdClass: 'table-row-expand', 194 }, 195 ... 196 ], 197 expandRowLabel 198 } 199 } 200} 201</script> 202``` 203 204## Search 205 206The table is leveraging 207[BootstrapVue table filtering](https://bootstrap-vue.org/docs/components/table#filtering) 208for search. Add the 209[@filtered](https://bootstrap-vue.org/docs/components/table#filter-events) event 210listener onto the `<b-table>` component. The event callback should track the 211total filtered items count. 212 213Import the `<search>` and `<table-cell-count>` components and include them in 214the template above the `<b-table>` component. 215 216Include the 217[SearchFilterMixin](https://github.com/openbmc/webui-vue/blob/master/src/components/Mixins/SearchFilterMixin.js). 218Add the `@change-search` and `@clear-search` event listeners on the `<search>` 219component and use the corresponding `onChangeSearchInput` and 220`onClearSearchInput` methods as the event callbacks. The table should also 221include the dynamic `:filter` prop with `searchFilter` set as the value. 222 223The `<table-cell-count>` component requires two properties, total table item 224count and total filtered items count. 225 226Add the `:empty-filtered-text` prop to the table to show the translated message 227if there are no search matches. 228 229 230 231 232 233 234 235```vue 236<template> 237 <b-container> 238 <b-row> 239 <b-col> 240 <search 241 @changeSearch="onChangeSearchInput" 242 @clearSearch="onClearSearchInput" 243 /> 244 </b-col> 245 <b-col> 246 <table-cell-count 247 :filtered-items-count="filteredItemsCount" 248 :total-number-of-cells="items.length" 249 /> 250 </b-col> 251 </b-row> 252 <b-table 253 hover 254 responsive="md" 255 :items="items" 256 :fields="fields" 257 :filter="searchFilter" 258 :empty-filtered-text="$t('global.table.emptySearchMessage')" 259 @filtered="onFiltered" 260 /> 261 </b-container> 262</template> 263<script> 264import Search from '@/components/Global/Search'; 265import TableCellCount from '@/components/Global/TableCellCount'; 266import SearchFilterMixin, { searchFilter } from '@/components/Mixins/SearchFilterMixin'; 267 268export default { 269 components: { Search, TableCellCount }, 270 mixins: [ SearchFilterMixin ], 271 data() { 272 return { 273 items: [...], 274 fields: [...], 275 searchFilter, 276 filteredItems: [], 277 } 278 }, 279 computed: { 280 filteredItemsCount() { 281 return this.filteredItems.length; 282 }, 283 }, 284 methods: { 285 onFiltered(items) { 286 this.filteredItems = items; 287 }, 288 }, 289} 290</script> 291``` 292 293## Row actions 294 295To add table row actions, add a column for the action buttons in the table. Then 296in the array of table items, add a corresponding array of actions for each item. 297The array should have each desired row action with a `value` and `title` 298property. 299 300Import the `<table-row-action>` component. Provide the `value` and `title` props 301to the component and use the named `#icons` slot to include an icon. The 302component will emit a `@click-table-action` with the event value. 303 304 305 306```vue 307<template> 308 <b-table 309 hover 310 responsive="md" 311 :items="itemsWithActions" 312 :fields="fields" 313 > 314 <template #cell(actions)="row"> 315 <table-row-action 316 v-for="(action, index) in row.item.actions" 317 :key="index" 318 :value="action.value" 319 :title="action.title" 320 @click-table-action="onTableRowAction($event, row.item)" 321 /> 322 <template #icon> 323 <icon-edit v-if="action.value === 'edit'"/> 324 <icon-delete v-if="action.value === 'delete'"/> 325 </template> 326 </table-row-action> 327 </template> 328 </b-table> 329</template> 330<script> 331import IconDelete from '@carbon/icons-vue/es/trash-can/20'; 332import IconEdit from '@carbon/icons-vue/es/edit/20'; 333import TableRowAction from '@/components/Global/TableRowAction'; 334 335export default { 336 components: { IconDelete, IconEdit, TableRowAction }, 337 data() { 338 return { 339 items: [...], 340 fields: [ 341 ..., 342 { 343 key: 'actions', 344 label: '', 345 tdClass: 'text-right text-nowrap', 346 } 347 ], 348 } 349 }, 350 computed: { 351 itemsWithActions() { 352 return this.items.map((item) => { 353 return { 354 ...item, 355 actions: [ 356 { 357 value: 'edit', 358 title: this.$t('global.action.edit'), 359 }, 360 { 361 value: 'delete', 362 title: this.$t('global.action.delete'), 363 }, 364 ], 365 }; 366 }); 367 } 368 }, 369 methods: { 370 onTableRowAction(event, row) { 371 // row action callback 372 } 373 } 374} 375</script> 376``` 377 378## Filters 379 380To add a table dropdown filter: 381 3821. Import the `<table-filter> `component and TableFilterMixin. 3831. Add a filters prop to the `<table-filters>` component. This prop should be an 384 array of filter groups–each required to have a key, label, and values prop. 385 386The `label` prop value should be the translated filter group label. The `key` 387prop will usually match the filtered by table column key. The `values` prop 388should be an array of filter values that will render as a list of checkbox items 389in the dropdown. 390 391The component will emit a `@filter-change` event that will provide the filter 392group and all selected values in the group. Use the getFilteredTableData method 393from the TableFilterMixin to show the filtered table data. 394 395 396 397 398 399```vue 400<template> 401 <b-container> 402 <b-row> 403 <b-col class="text-right"> 404 <table-filter 405 :filters="tableFilters" 406 @filter-change="onTableFilterChange" 407 /> 408 </b-col> 409 </b-row> 410 <b-table hover responsive="md" :items="filteredItems" :fields="fields" /> 411 </b-container> 412</template> 413<script> 414import TableFilter from '@/components/Global/TableFilter'; 415import TableFilterMixin from '@/components/Mixins/TableFilterMixin'; 416 417export default { 418 components: { TableFilter }, 419 mixins: [ TableFilterMixin ], 420 data() { 421 return { 422 items: [...], 423 fields: [...], 424 tableFilters: [ 425 { 426 label: this.$t('table.status'), 427 key: status, 428 values: ['Open', 'Closed'] 429 } 430 ], 431 activeFilters: [], 432 }, 433 }, 434 computed: { 435 filteredItems() { 436 return this.getFilteredTableData(this.items, this.activeFilters); 437 }, 438 }, 439 methods: { 440 onTableFilterChange({ activeFilters }) { 441 this.activeFilters = activeFilters; 442 }, 443 }, 444} 445</script> 446``` 447 448### Date filter 449 450To add a date filter, import the `<table-date-filter>` component. It will emit a 451`@change` event with the user input date values. There is a date filter method, 452`getFilteredTableDataByDate`, in the `TableFilterMixin`. 453 454## Batch actions 455 456Batch actions allow a user to take a single action on many items in a table at 457once. 458 459To add table batch actions: 460 4611. Import the `<table-toolbar> `component and BVTableSelectableMixin 4621. Add the `selectable`, `no-select-on-click` props and a unique `ref` to the 463 table. The table will emit a `@row-selected` event. Use the `onRowSelected` 464 mixin method as a callback and provide the `$event` as the first argument and 465 the total table items count as the second argument. 4661. Add a table column for checkboxes. The table header checkbox should use the 467 `tableHeaderCheckboxModel` and `tableHeaderCheckboxIndeterminate` values 468 provided by the mixin. The table header checkbox should also use the 469 `onChangeHeaderCheckbox` method as a callback for the `@change` event with 470 the table `ref` passed as an argument. The table row checkboxes should use 471 the `toggleSelectRow` method as a callback for the `@change` event with the 472 table `ref` passed as the first argument and the row index passed as the 473 second argument. 4741. Add an actions prop to the `<table-toolbar>` component. This prop should be 475 an array of toolbar actions–required to have a value and label prop. Add the 476 `selected-items-count` prop to the `<table-toolbar>` component. The component 477 will emit a `@batch-action` event that will provide the user selected action. 478 It will also emit a `@clear-selected` event. Provide the `clearSelectedRows` 479 as a callback with the table `ref` passed as an argument. 480 481 482 483 484 485```vue 486<template> 487 <b-container> 488 <table-toolbar 489 :selected-items-count="selectedRows.length" 490 :actions="tableToolbarActions" 491 @clear-selected="clearSelectedRows($refs.table)" 492 @batch-action="onBatchAction" 493 /> 494 <b-table 495 ref="table" 496 hover 497 selectable 498 no-select-on-click 499 responsive="md" 500 :items="filteredItems" 501 :fields="fields" 502 @row-selected="onRowSelected($event, items.length)" 503 > 504 <template #head(checkbox)> 505 <b-form-checkbox 506 v-model="tableHeaderCheckboxModel" 507 :indeterminate="tableHeaderCheckboxIndeterminate" 508 @change="onChangeHeaderCheckbox($refs.table)" 509 /> 510 </template> 511 <template #cell(checkbox)="row"> 512 <b-form-checkbox 513 v-model="row.rowSelected" 514 @change="toggleSelectRow($refs.table, row.index)" 515 /> 516 </template> 517 </b-table> 518 </b-container> 519</template> 520<script> 521import TableToolbar from '@/components/Global/TableToolbar'; 522import BVTableSelectableMixin, { 523 tableHeaderCheckboxModel, 524 tableHeaderCheckboxIndeterminate, 525 selectedRows 526} from '@/components/Mixins/BVTableSelectableMixin'; 527 528export default { 529 components: { TableToolbar }, 530 mixins: [ BVTableSelectableMixin ], 531 data() { 532 return { 533 items: [...], 534 fields: [ 535 { 536 key: 'checkbox' 537 }, 538 ... 539 ], 540 tableToolbarActions: [ 541 { 542 value: 'edit', 543 label: this.$t('global.action.edit') 544 }, 545 { 546 value: 'delete', 547 label: this.$t('global.action.delete') 548 }, 549 ], 550 tableHeaderCheckboxModel, 551 tableHeaderCheckboxIndeterminate, 552 selectedRows 553 }, 554 }, 555 methods: { 556 onBatchAction(action) { 557 // Do something with selected batch action and selected rows 558 }, 559 }, 560} 561</script> 562``` 563 564## Pagination 565 566To add table pagination: 567 5681. Import the BVPaginationMixin 5691. Add the `per-page` and `current-page` props to the `<table>` component. 5701. Add the below HTML snippet to the template. Make sure to update the 571 `total-rows` prop. 572 573```vue{21} 574<b-row> 575 <b-col sm="6"> 576 <b-form-group 577 class="table-pagination-select" 578 :label="$t('global.table.itemsPerPage')" 579 label-for="pagination-items-per-page" 580 > 581 <b-form-select 582 id="pagination-items-per-page" 583 v-model="perPage" 584 :options="itemsPerPageOptions" 585 /> 586 </b-form-group> 587 </b-col> 588 <b-col sm="6"> 589 <b-pagination 590 v-model="currentPage" 591 first-number 592 last-number 593 :per-page="perPage" 594 :total-rows="getTotalRowCount(items.length)" 595 aria-controls="table-event-logs" 596 /> 597 </b-col> 598</b-row> 599``` 600 601 602 603```vue 604<template> 605 <b-container> 606 <b-table 607 hover 608 responsive="md" 609 :items="filteredItems" 610 :fields="fields" 611 :per-page="perPage" 612 :current-page="currentPage" 613 /> 614 <b-row> 615 <b-col sm="6"> 616 <b-form-group 617 class="table-pagination-select" 618 :label="$t('global.table.itemsPerPage')" 619 label-for="pagination-items-per-page" 620 > 621 <b-form-select 622 id="pagination-items-per-page" 623 v-model="perPage" 624 :options="itemsPerPageOptions" 625 /> 626 </b-form-group> 627 </b-col> 628 <b-col sm="6"> 629 <b-pagination 630 v-model="currentPage" 631 first-number 632 last-number 633 :per-page="perPage" 634 :total-rows="getTotalRowCount(items.length)" 635 aria-controls="table-event-logs" 636 /> 637 </b-col> 638 </b-row> 639 </b-container> 640</template> 641<script> 642import BVPaginationMixin, { 643 currentPage, 644 perPage, 645 itemsPerPageOptions 646} from '@/components/Mixins/BVPaginationMixin'; 647 648export default { 649 mixins: [ BVPaginationMixin ], 650 data() { 651 return { 652 items: [...], 653 fields: [..], 654 currentPage, 655 perPage, 656 itemsPerPageOptions 657 }, 658 } 659} 660</script> 661``` 662