To make good looking Vue apps, we need to style our components.
To make our lives easier, we can use components with styles built-in.
We look at how to customize table contents.
Colgroups
We can group table columns into colgroups.
For example, we can write:
<template>
<div id="app">
<b-table :items="items">
<template v-slot:table-colgroup="scope">
<col
v-for="field in scope.fields"
:key="field.key"
:style="{ width: field.key === 'firstName' ? '120px' : '180px' }"
>
</template>
</b-table>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ firstName: "alex", lastName: "green" },
{
firstName: "may",
lastName: "smith"
},
{ firstName: "james", lastName: "jones" }
]
};
}
};
</script>
We have the col
component that populates the table-colgroup
slot to loop through the fields.
This way, we can style each column with the style
prop.
Busy State
b-table
lets us pass in the busy
prop to flag the table if it’s busy.
This way, we can display something if the table is busy.
For example, we can write:
<template>
<div id="app">
<b-table :items="items" busy>
<template v-slot:table-busy>
<div>
<b-spinner></b-spinner>
<strong>Loading...</strong>
</div>
</template>
</b-table>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ firstName: "alex", lastName: "green" },
{
firstName: "may",
lastName: "smith"
},
{ firstName: "james", lastName: "jones" }
]
};
}
};
</script>
We have the busy
prop on b-table
and populated the table-busy
slow with a spinner and the ‘Loading’ text.
Therefore, instead of seeing the table’s content, we’ll see what’s in the slot instead.
Custom Data Rendering
We can render data in a custom way.
For example, we can write:
<template>
<div id="app">
<b-table :items="items">
<template v-slot:cell(firstName)="data">{{ data.value }}</template>
<template v-slot:cell(lastName)="data">
<b>{{ data.value }}</b>
</template>
</b-table>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ firstName: "alex", lastName: "green" },
{
firstName: "may",
lastName: "smith"
},
{ firstName: "james", lastName: "jones" }
]
};
}
};
</script>
We populate the slots for the columns.
The column’s data can be obtained with data
.
v-slot:cell(firstName)=”data”
gets the firstName
property and assigned it to data
.
v-slot:cell(lastName)=”data”
does the same for lastName
.
And the value
property has the value of each property.
Therefore, we can render each piece of data our way.
data
in the example above has many properties.
index
has the row number.
item
has the raw record of each entry.
value
is the value for the given key.
unformatted
has raw values before passing through the formatter
function.
field
has the normalized field definition object.
detailsShowing
is true
if the row-details
scoped slot is visible.
toggleDetails
can be called to toggle the visibility of the row-details
scope slot.
rowSelected
is true
if the row is selected.
selectRow
selects the current row when called.
unselectRow
unselects the current row when called.
Display Raw HTML
We can display raw HTML.
To do that we just populate the slot with an element that has the v-html
directive.
For instance, we can write:
<template>
<div id="app">
<b-table :items="items">
<template v-slot:cell(lastName)="data">
<span v-html="data.value"></span>
</template>
</b-table>
</div>
</template>
<script>
export default {
data() {
return {
items: [{ firstName: "alex", lastName: "<b>green</b>" }]
};
}
};
</script>
We have a span that has the v-html
directive set to data.value
which has our lastName
‘s value.
So the HTML code will be rendered without sanitization.
However, we have to be careful so that we don’t get attacked with cross-site scripting attacks.
Formatter Callback
We can add a formatted to out fields
array entries to format our cells.
For instance, we can write:
<template>
<div id="app">
<b-table :items="items" :fields="fields"></b-table>
</div>
</template>
<script>
export default {
data() {
return {
fields: [
{
key: "name",
label: "Full Name",
formatter: "fullName"
}
],
items: [
{ firstName: "alex", lastName: "green" },
{
firstName: "may",
lastName: "smith"
},
{ firstName: "james", lastName: "jones" }
]
};
},
methods: {
fullName(value, key, item) {
return `${item.firstName} ${item.lastName}`;
}
}
};
</script>
We have the fullName
method.
It takes the item
parameter, which has the object in items
, and return the firstName
and lastName
properties combined together.
The name of it is set as the value of formatter
in our field’s array entry.
Therefore, now we have one Full Name column that has both field’s values displayed together.
We can also write:
<template>
<div id="app">
<b-table :items="items" :fields="fields"></b-table>
</div>
</template>
<script>
export default {
data() {
return {
fields: [
{
key: "name",
label: "Full Name",
formatter(value, key, item) {
return `${item.firstName} ${item.lastName}`;
}
}
],
items: [
{ firstName: "alex", lastName: "green" },
{
firstName: "may",
lastName: "smith"
},
{ firstName: "james", lastName: "jones" }
]
};
}
};
</script>
We moved the formatted function to fields
entry object instead of having it in methods
.
Photo by Marylou Fortier on Unsplash
Conclusion
We can format table cells with formatted functions.
Also, we can customize cell layout and formatting with slots or raw HTML.
We can set the busy state to display something when the table’s data is loading.