Skip to content

Commit fc083e5

Browse files
emanuelmutschlechnerpi0
authored andcommitted
feat(table): support custom attributes per table cell in a column (bootstrap-vue#1760)
1 parent 1ce1a20 commit fc083e5

File tree

4 files changed

+46
-27
lines changed

4 files changed

+46
-27
lines changed

src/components/table/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ The following field properties are recognized:
279279
| `thClass` | String or Array | Class name (or array of class names) to add to `<thead>`/`<tfoot>` heading `<th>` cell.
280280
| `thStyle` | Object | JavaScript object representing CSS styles you would like to apply to the table `<thead>`/`<tfoot>` field `<th>`.
281281
| `variant` | String | Apply contextual class to all the `<th>` **and** `<td>` in the column - `active`, `success`, `info`, `warning`, `danger` (these variants map to classes `thead-${variant}`, `table-${variant}`, or `bg-${variant}` accordingly).
282-
| `tdAttr` | Object | JavaScript object representing additional attributes to apply to the `<tbody>` field `td` cell.
282+
| `tdAttr` | Object or Function | JavaScript object representing additional attributes to apply to the `<tbody>` field `<td>` cell. If custom attributes per cell are required, a callback function can be specified instead.
283283
| `isRowHeader` | Boolean | When set to `true`, the field's item data cell will be rendered with `<th>` rather than the default of `<td>`.
284284

285285
>**Notes:**

src/components/table/fixtures/table.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ window.app = new Vue({
55
name: {
66
label: 'Person Full name',
77
sortable: true,
8-
tdClass: 'bg-primary'
8+
tdClass: 'bg-primary',
9+
tdAttr: {title: 'Person Full name'}
910
},
1011
age: {
1112
label: 'Person age',
@@ -15,11 +16,13 @@ window.app = new Vue({
1516
},
1617
isActive: {
1718
label: 'is Active',
18-
tdClass: (value, key, item) => { return 'bg-danger' }
19+
tdClass: (value, key, item) => { return 'bg-danger' },
20+
tdAttr: (value, key, item) => { return {title: 'is Active'} }
1921
},
2022
actions: {
2123
label: 'Actions',
22-
tdClass: 'formatCell'
24+
tdClass: 'formatCell',
25+
tdAttr: 'formatCellAttrs'
2326
}
2427
},
2528
currentPage: 1,
@@ -138,6 +141,9 @@ window.app = new Vue({
138141
},
139142
formatCell (value, key, item) {
140143
return ['bg-primary', 'text-light']
144+
},
145+
formatCellAttrs (value, key, item) {
146+
return {title: 'Actions'}
141147
}
142148
}
143149
})

src/components/table/table.js

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,9 @@ export default {
192192
const data = {
193193
key: `row-${rowIndex}-cell-${colIndex}`,
194194
class: this.tdClasses(field, item),
195-
attrs: field.tdAttr || {},
195+
attrs: this.tdAttrs(field, item, colIndex),
196196
domProps: {}
197197
}
198-
data.attrs['aria-colindex'] = String(colIndex + 1)
199198
let childNodes
200199
if ($scoped[field.key]) {
201200
childNodes = [
@@ -223,15 +222,6 @@ export default {
223222
childNodes = formatted
224223
}
225224
}
226-
if (this.isStacked) {
227-
// Generate the "header cell" label content in stacked mode
228-
data.attrs['data-label'] = field.label
229-
if (field.isRowHeader) {
230-
data.attrs['role'] = 'rowheader'
231-
} else {
232-
data.attrs['role'] = 'cell'
233-
}
234-
}
235225
// Render either a td or th cell
236226
return h(field.isRowHeader ? 'th' : 'td', data, childNodes)
237227
})
@@ -864,7 +854,6 @@ export default {
864854
]
865855
},
866856
tdClasses (field, item) {
867-
const t = this
868857
let cellVariant = ''
869858
if (item._cellVariants && item._cellVariants[field.key]) {
870859
cellVariant = `${this.dark ? 'bg' : 'table'}-${
@@ -877,9 +866,23 @@ export default {
877866
: '',
878867
cellVariant,
879868
field.class ? field.class : '',
880-
t.getTdClasses(item, field)
869+
this.getTdValues(item, field.key, field.tdClass, '')
881870
]
882871
},
872+
tdAttrs (field, item, colIndex) {
873+
let attrs = {}
874+
attrs['aria-colindex'] = String(colIndex + 1)
875+
if (this.isStacked) {
876+
// Generate the "header cell" label content in stacked mode
877+
attrs['data-label'] = field.label
878+
if (field.isRowHeader) {
879+
attrs['role'] = 'rowheader'
880+
} else {
881+
attrs['role'] = 'cell'
882+
}
883+
}
884+
return assign({}, attrs, this.getTdValues(item, field.key, field.tdAttr, {}))
885+
},
883886
rowClasses (item) {
884887
return [
885888
item._rowVariant
@@ -982,21 +985,19 @@ export default {
982985
this._providerSetLocal(data)
983986
}
984987
},
985-
getTdClasses (item, field) {
986-
const key = field.key
987-
const tdClass = field.tdClass
988+
getTdValues (item, key, tdValue, defValue) {
988989
const parent = this.$parent
989-
if (tdClass) {
990-
if (typeof tdClass === 'function') {
990+
if (tdValue) {
991+
if (typeof tdValue === 'function') {
991992
let value = get(item, key)
992-
return tdClass(value, key, item)
993-
} else if (typeof tdClass === 'string' && typeof parent[tdClass] === 'function') {
993+
return tdValue(value, key, item)
994+
} else if (typeof tdValue === 'string' && typeof parent[tdValue] === 'function') {
994995
let value = get(item, key)
995-
return parent[tdClass](value, key, item)
996+
return parent[tdValue](value, key, item)
996997
}
997-
return tdClass
998+
return tdValue
998999
}
999-
return ''
1000+
return defValue
10001001
},
10011002
getFormattedValue (item, field) {
10021003
const key = field.key

src/components/table/table.spec.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,18 @@ describe('table', async () => {
733733
tr.children[3].classList.contains('bg-primary') &&
734734
tr.children[3].classList.contains('text-light'))
735735
.toBe(true)
736+
expect(Boolean(tr.children[0]) &&
737+
Boolean(tr.children[0].attributes) &&
738+
tr.children[0].getAttribute('title') === 'Person Full name')
739+
.toBe(true)
740+
expect(Boolean(tr.children[2]) &&
741+
Boolean(tr.children[2].attributes) &&
742+
tr.children[2].getAttribute('title') === 'is Active')
743+
.toBe(true)
744+
expect(Boolean(tr.children[3]) &&
745+
Boolean(tr.children[3].attributes) &&
746+
tr.children[3].getAttribute('title') === 'Actions')
747+
.toBe(true)
736748
}
737749
})
738750
})

0 commit comments

Comments
 (0)