Vue element-ui <el-table-column> formatter – how to display html?
Solution 1
Ok, after a few hours of brainstorming I found pretty nice solution. I'm putting it here for others - I hope this helps somebody.
Value displayed in custom column can be:
-
simple string (prop)
-
formatted string (safe, without any html or components, via original formatter)
-
customized value (html, component, also safe!)
In order to achieve this, I had to create custom formatter components, which I put in folder i.e. /TableFormatters/
For this purpose, there is simple functional component DatetimeFormatter that display date-time with icon.
TableFormatters/DatetimeFormatter.vue
<template functional>
<span>
<i class="icon-date"></i> {{ props.row[props.column] }}
</span>
</template>
<script>
export default {
name: 'DatetimeFormatter',
}
</script>
Here come's columns configuration:
import DatetimeFormatter from './TableFormatters/DatetimeFormatter'
// ...
data() {
return {
data: [/*...*/],
columns: [
name: {
label: 'Name',
},
state: {
label: 'State',
formatter: row => {
return 'State: '+row.state__label
}
},
created_at: {
label: 'Created at',
formatter: DatetimeFormatter
}
]
}
}
Now it's time to define <el-table>
:
<el-table :data="data">
<el-table-column
v-for="(column, index) in columns"
:key="index"
:label="columns[column] ? columns[column].label : column"
:prop="column"
:formatter="typeof columns[column].formatter === 'function' ? columns[column].formatter : null">
<template #default="{row}" v-if="typeof columns[column].formatter !== 'function'">
<div v-if="columns[column].formatter"
:is="columns[column].formatter"
:row="row"
:column="column">
</div>
<template v-else>
{{ row[column] }}
</template>
</template>
</el-table-column>
</el-table>
This works like a charm. What's going on here with formatter?
First we check if the formatter is set as a function
. If so, the native <el-table-column>
formatter takes the control, because <template #default={row}>
will not be created. Otherwise formatter component will be created (via :is
attribute). However, it there is no formatter, the plain value for a row will be shown.
Solution 2
If you want to render custom HTML for a <el-table-column>
, you will need to make use of the custom column template functionality, rather than the :formatter
prop. It's going to look something like this:
<el-table :data="data">
<el-table-column
v-for="(column, index) in columns"
:key="index"
:label="column.label"
>
<template slot-scope="scope">
<span class="date">{{ scope.row.value }}</span>
</template>
</el-table-column>
</el-table>
In the general case, you can make use of the v-html
directive if you need to render unescaped HTML. There are some security implications involved, so make sure you understand those before reaching for v-html
.
Essentially, it boils down to this: never use v-html
to render content that was provided by the user.
Related videos on Youtube
Comments
-
Daniel almost 2 years
How to return html formatted cell value?
I want to get custom formatted value (with html or other components) with
<el-table-column>
formatter
.<el-table :data="data"> <el-table-column v-for="(column, index) in columns" :key="index" :label="column.label" :formatter="column.formatter"> </el-table-column> </el-table>
data() { return { columns: [ { label: 'Created at', formatter: (row, col, value, index) => { return `<span class="date">${value}</span>` } }, // edit: { label: 'Address', formatter: (row, col, value, index) => { return `<mini-map :data="${row}"></mini-map>` } } // other dynamic columns... ] } }
But cell content is displayed as escaped html string. Is there any possibility to force html?
EPIC EDIT: I added an answer with a solution.
-
Daniel over 4 yearsThanks, I used
<template slot-scope="scope">
before with static table columns template. But what with more columns with custom formatters? *I have updated my question by adding more sample columns. -
dreijntjens over 4 yearsIt's is better to use
v-slot
instead ofslot-scope
as it is deprecated, and it will even be nicer with destructuring:<template v-slot:default="{ row }")>
or shorter<template #default="{ row }">
-
Daniel over 4 yearsthanks, but I need full custom template (with html etc.) for each column. I added answer with solution that I found.
-
chans over 4 yearsThanks for the update, if my solutions helps you, you can upvote this answer as well
-
commonpike over 3 yearsThat's nice, but it doesn't tell us if/how this displays html, which was the question ?
-
dguay over 2 yearsThis is working very well thank you. Is it possible to not use a functional component or does it have to? I've tried but it doesn't seem to work.
-
Daniel over 2 years@dguay you can also use normal components as well, but you need directly define
row
andcolumn
props. -
dguay over 2 yearswell I thought I tried that but you're right that works. Thanks !