Starting with v1.15.2, the Bootstrap Table adds support for the Bootstrap Table Vue component.

We can use the two column options formatter and events to implement custom display and event listen for columns:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<template>
  <BootstrapTable
    :columns="columns"
    :data="data"
    :options="options"
  />
</template>

<script>
import BootstrapTable from 'bootstrap-table/dist/bootstrap-table-vue.esm.js'

export default {
  components: {
    BootstrapTable
  },
  data () {
    return {
      columns: [
        {
          title: 'Item ID',
          field: 'id'
        },
        {
          field: 'name',
          title: 'Item Name'
        },
        {
          field: 'price',
          title: 'Item Price'
        },
        {
          field: 'actions',
          title: 'Actions',
          formatter: () => {
            return '<button class="btn btn-secondary">Click</button>'
          },
          events: {
            'click .btn': (e, value, row) => {
              this.clickRow(row)
            }
          }
        }
      ],
      data: [
        {
          id: 1,
          name: 'Item 1',
          price: '$1'
        }
      ],
      options: {
        search: true,
        showColumns: true
      }
    }
  },
  methods: {
    clickRow (row) {
      alert(JSON.stringify(row))
    }
  }
}
</script>

Here’s an online example: https://live.bootstrap-table.com/code/wenzhixin/440

As you can see, the clickRow method is called when we click the button, but we are using the event binding method of jQuery.

With vue, you might wonder if I can bind using the event of vue?

Such as:

1
2
3
formatter: (value, row) => {
  return '<button class="btn btn-secondary" @click="clickRow(row)">Click</button>'
}

The answer is no, because the event of vue is not handled here.

In addition, we may use the UI component of vue, for example BootstrapVue , then you might wonder, can the formatter here use the vue component?

Such as:

1
2
3
formatter: (value, row) => {
  return '<b-button @click="clickRow(row)">Click</b-button>'
}

Of course, this is also not supported. What should we do?

For these two questions, I conducted in-depth research and experimentation. Fortunately, a viable solution was found.

The technical principle is mainly to save the vue component to a custom variable, and then return a simple div containing only class. After the table is rendered, we will convert it to the corresponding vue Component.

We have added a method:

1
2
3
4
5
6
7
8
9
vueFormatter (obj) {
  const key = `_vue_formatter_${this.vueFormatters.length}`
  this.vueFormatters.push({
    el: `.${key}`,
    name: key,
    ...obj
  })
  return `<div class="${key}"/>`
}

You can see that we use the vueFormatters variable to save the vue component information for all columns.

We know that the rendered event of the table is onPostBody, which we listen to and render the saved vue component information:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
vueFormatterPostBody () {
  if (!this.vueFormatters.length) {
    return
  }

  for (let i = this.vueFormatters.length - 1; i >= 0; i--) {
    const formatter = this.vueFormatters[i]

    if (document.getElementsByClassName(formatter.name)) {
      new Vue(formatter)
      this.vueFormatters.splice(i, 1)
    }
  }
}

Considering that we will reuse it often, we create a mixins/table.js file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import Vue from 'vue/dist/vue.esm.js'

export default {
  data () {
    return {
      vueFormatters: []
    }
  },

  methods: {
    vueFormatter (obj) {
      const key = `_vue_formatter_${this.vueFormatters.length}`
      this.vueFormatters.push({
        el: `.${key}`,
        name: key,
        ...obj
      })
      return `<div class="${key}"/>`
    },

    vueFormatterPostBody () {
      if (!this.vueFormatters.length) {
        return
      }

      for (let i = this.vueFormatters.length - 1; i >= 0; i--) {
        const formatter = this.vueFormatters[i]

        if (document.getElementsByClassName(formatter.name)) {
          new Vue(formatter)
          this.vueFormatters.splice(i, 1)
        }
      }
    }
  }
}

How to use:

1
2
3
4
5
6
7
8
9
formatter: (value, row) => {
  return this.vueFormatter({
    template: '<b-button @click="clickRow(row)">Click</b-button>',
    data: { row },
    methods: {
      clickRow: this.clickRow
    }
  })
}
1
2
3
4
5
6
7
<BootstrapTable
  ref="table"
  :columns="columns"
  :data="data"
  :options="options"
  @onPostBody="vueFormatterPostBody"
/>

Online example: https://live.bootstrap-table.com/code/wenzhixin/441

Things to note:

Since new Vue({ template }) requires a full build version, if used in webpack, you need to modify all the vue import:

1
import Vue from 'vue/dist/vue.esm.js'

Or we can alias Vue import:

1
2
3
4
5
resolve: {
  alias: {
    vue$: 'vue/dist/vue.esm.js'
  }
}

Source code: https://github.com/wenzhixin/bootstrap-table-examples/tree/develop/vue-starter

Finally, hope this article can help you.